From 5780c239e4cdcd4389eed37a96d19a98154ebe03 Mon Sep 17 00:00:00 2001 From: ruv Date: Sun, 2 Aug 2026 15:22:13 -0400 Subject: [PATCH] security: repair scanning and close stale alert sources --- .github/workflows/aether-arena-harness.yml | 4 +- .github/workflows/bench-regression.yml | 14 +- .github/workflows/bfld-mqtt-integration.yml | 6 +- .github/workflows/cd.yml | 22 +-- .github/workflows/ci.yml | 60 ++++---- .github/workflows/clone-tracking.yml | 2 +- .github/workflows/cog-ha-matter-release.yml | 26 ++-- .github/workflows/dashboard-a11y.yml | 6 +- .github/workflows/dashboard-pages.yml | 10 +- .github/workflows/desktop-release.yml | 24 +-- .github/workflows/firmware-ci.yml | 6 +- .github/workflows/firmware-qemu.yml | 22 +-- .github/workflows/fix-regression-guard.yml | 6 +- .github/workflows/mqtt-integration.yml | 6 +- .github/workflows/nvsim-server-docker.yml | 10 +- .github/workflows/pip-release.yml | 38 ++--- .github/workflows/pointcloud-pages.yml | 4 +- .github/workflows/python-ci.yml | 16 +- .github/workflows/ruview-swarm-ci.yml | 20 +-- .github/workflows/security-scan.yml | 156 ++++++-------------- .github/workflows/semconv.yml | 4 +- .github/workflows/sensing-server-docker.yml | 12 +- .github/workflows/threejs-pages.yml | 4 +- .github/workflows/update-submodules.yml | 2 +- .github/workflows/verify-pipeline.yml | 4 +- aether-arena/calibration/calibrate.py | 5 +- aether-arena/calibration/infer.py | 5 +- docker/Dockerfile.rust | 2 - docker/docker-compose.yml | 40 ++++- docker/otel-compose.yml | 54 ++++++- firmware/esp32-csi-node/main/c6_softap_he.c | 2 +- firmware/esp32-csi-node/main/main.c | 15 +- firmware/esp32-csi-node/main/nvs_config.c | 21 +-- firmware/esp32-csi-node/main/wasm_runtime.c | 3 +- firmware/esp32-csi-node/main/wasm_upload.c | 4 +- firmware/esp32-csi-node/provision.py | 4 +- logging/fluentd-config.yml | 75 +++++++++- scripts/generate_nvs_matrix.py | 4 +- scripts/occworld_retrain.py | 5 +- scripts/occworld_server.py | 3 +- scripts/provision.py | 4 +- v2/crates/nvsim-server/Dockerfile | 10 +- vendor/metaharness | 2 +- vendor/midstream | 2 +- vendor/rufield | 2 +- vendor/ruvector | 2 +- vendor/rvcsi | 2 +- vendor/sublinear-time-solver | 2 +- 48 files changed, 427 insertions(+), 325 deletions(-) diff --git a/.github/workflows/aether-arena-harness.yml b/.github/workflows/aether-arena-harness.yml index a0d946da..97489329 100644 --- a/.github/workflows/aether-arena-harness.yml +++ b/.github/workflows/aether-arena-harness.yml @@ -32,7 +32,7 @@ jobs: run: working-directory: v2 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -40,7 +40,7 @@ jobs: run: rustup show && rustc --version - name: Cache cargo - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry diff --git a/.github/workflows/bench-regression.yml b/.github/workflows/bench-regression.yml index 1defa9bb..3ad5a6cb 100644 --- a/.github/workflows/bench-regression.yml +++ b/.github/workflows/bench-regression.yml @@ -71,7 +71,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout (recursive — wifi-densepose-rufield path-deps vendor/rufield) - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: # The workspace includes `wifi-densepose-rufield`, which path-deps the # `vendor/rufield` submodule crates. Without a recursive checkout the @@ -100,10 +100,10 @@ jobs: pkg-config - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Cache cargo (Swatinem/rust-cache) - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with: workspaces: v2 # Distinct cache scope from ci.yml's rust-tests so the bench profile @@ -150,15 +150,15 @@ jobs: needs: [bench-compile] steps: - name: Checkout (recursive) - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Cache cargo (Swatinem/rust-cache) - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with: workspaces: v2 key: bench-regression @@ -192,7 +192,7 @@ jobs: - name: Upload informational bench logs if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: bench-fast-run-logs path: bench-out/ diff --git a/.github/workflows/bfld-mqtt-integration.yml b/.github/workflows/bfld-mqtt-integration.yml index 4104b21d..e2269a63 100644 --- a/.github/workflows/bfld-mqtt-integration.yml +++ b/.github/workflows/bfld-mqtt-integration.yml @@ -52,17 +52,17 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: components: clippy - name: Cache cargo registry + target - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index dcbfee8b..7d0b299c 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -44,7 +44,7 @@ jobs: image_tag: ${{ steps.determine-tag.outputs.tag }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: ref: ${{ github.event.workflow_run.head_sha || github.sha }} submodules: recursive @@ -96,12 +96,12 @@ jobs: url: https://staging.wifi-densepose.com steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up kubectl - uses: azure/setup-kubectl@v3 + uses: azure/setup-kubectl@901a10e89ea615cf61f57ac05cecdf23e7de06d8 with: version: 'v1.28.0' @@ -147,12 +147,12 @@ jobs: url: https://wifi-densepose.com steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up kubectl - uses: azure/setup-kubectl@v3 + uses: azure/setup-kubectl@901a10e89ea615cf61f57ac05cecdf23e7de06d8 with: version: 'v1.28.0' @@ -222,7 +222,7 @@ jobs: # kubectl scale rs -n wifi-densepose -l app=wifi-densepose,version!=green --replicas=0 - name: Upload deployment artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: production-deployment-${{ github.run_number }} path: | @@ -239,7 +239,7 @@ jobs: name: ${{ needs.pre-deployment.outputs.deploy_env }} steps: - name: Set up kubectl - uses: azure/setup-kubectl@v3 + uses: azure/setup-kubectl@901a10e89ea615cf61f57ac05cecdf23e7de06d8 with: version: 'v1.28.0' @@ -293,7 +293,7 @@ jobs: done - name: Update deployment status - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b with: script: | const deployEnv = '${{ needs.pre-deployment.outputs.deploy_env }}'; @@ -317,7 +317,7 @@ jobs: steps: - name: Notify Slack on success if: needs.deploy-production.result == 'success' || needs.deploy-staging.result == 'success' - uses: 8398a7/action-slack@v3 + uses: 8398a7/action-slack@77eaa4f1c608a7d68b38af4e3f739dcd8cba273e with: status: success channel: '#deployments' @@ -331,7 +331,7 @@ jobs: - name: Notify Slack on failure if: needs.deploy-production.result == 'failure' || needs.deploy-staging.result == 'failure' - uses: 8398a7/action-slack@v3 + uses: 8398a7/action-slack@77eaa4f1c608a7d68b38af4e3f739dcd8cba273e with: status: failure channel: '#deployments' @@ -344,7 +344,7 @@ jobs: - name: Create deployment issue on failure if: needs.deploy-production.result == 'failure' - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b with: script: | github.rest.issues.create({ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a85b6a97..8f73bf4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,14 +27,14 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive fetch-depth: 0 - name: Set up Python continue-on-error: true - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' @@ -68,7 +68,7 @@ jobs: - name: Upload security reports continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 if: always() with: name: security-reports @@ -82,7 +82,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive # ADR-262 P1: `wifi-densepose-rufield` path-deps the `vendor/rufield` @@ -112,7 +112,7 @@ jobs: pkg-config - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # Swatinem/rust-cache replaces a naive `actions/cache` of the whole # `v2/target`. That manual cache of a 38-crate target dir (multi-GB) was an @@ -123,7 +123,7 @@ jobs: # reliably (and faster) on large workspaces. `workspaces: v2` points it at # the v2/ cargo workspace (keys on v2/Cargo.lock, caches v2/target). - name: Cache cargo (Swatinem/rust-cache) - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with: workspaces: v2 @@ -196,10 +196,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: '22' @@ -222,6 +222,8 @@ jobs: postgres: image: postgres:15 env: + # Ephemeral CI-only credential; this service is isolated to the job. + # kics-scan ignore-line POSTGRES_PASSWORD: postgres POSTGRES_DB: test_wifi_densepose options: >- @@ -245,13 +247,13 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up Python ${{ matrix.python-version }} continue-on-error: true - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: ${{ matrix.python-version }} cache: 'pip' @@ -266,6 +268,8 @@ jobs: - name: Run unit tests continue-on-error: true env: + # Ephemeral CI-only service URL; never used outside this job. + # kics-scan ignore-line DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose REDIS_URL: redis://localhost:6379/0 ENVIRONMENT: test @@ -275,6 +279,8 @@ jobs: - name: Run integration tests continue-on-error: true env: + # Ephemeral CI-only service URL; never used outside this job. + # kics-scan ignore-line DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose REDIS_URL: redis://localhost:6379/0 ENVIRONMENT: test @@ -283,7 +289,7 @@ jobs: - name: Upload coverage reports continue-on-error: true - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f with: files: ./coverage.xml flags: unittests @@ -291,7 +297,7 @@ jobs: - name: Upload test results continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 if: always() with: name: test-results-${{ matrix.python-version }} @@ -312,12 +318,12 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' @@ -361,7 +367,7 @@ jobs: - name: Upload performance results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: performance-results path: archive/v1/perf-junit.xml @@ -382,17 +388,17 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up Docker Buildx continue-on-error: true - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - name: Log in to Container Registry continue-on-error: true - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -401,7 +407,7 @@ jobs: - name: Extract metadata continue-on-error: true id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | @@ -412,7 +418,7 @@ jobs: - name: Build and push Docker image continue-on-error: true - uses: docker/build-push-action@v7 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a with: context: . target: production @@ -441,7 +447,7 @@ jobs: - name: Upload Trivy scan results continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 if: always() with: sarif_file: 'trivy-results.sarif' @@ -456,12 +462,12 @@ jobs: contents: write # gh-pages deploy needs write (GITHUB_TOKEN is read-only by default -> 403) steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' @@ -484,7 +490,7 @@ jobs: " - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v4 + uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 continue-on-error: true # openapi generation above is the real validation; deploy is best-effort (Pages may be disabled) with: github_token: ${{ secrets.GITHUB_TOKEN }} @@ -507,7 +513,7 @@ jobs: steps: - name: Notify Slack on success if: ${{ env.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }} - uses: 8398a7/action-slack@v3 + uses: 8398a7/action-slack@77eaa4f1c608a7d68b38af4e3f739dcd8cba273e with: status: success channel: '#ci-cd' @@ -515,7 +521,7 @@ jobs: - name: Notify Slack on failure if: ${{ env.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure') }} - uses: 8398a7/action-slack@v3 + uses: 8398a7/action-slack@77eaa4f1c608a7d68b38af4e3f739dcd8cba273e with: status: failure channel: '#ci-cd' @@ -523,7 +529,7 @@ jobs: - name: Create GitHub Release if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success' - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 with: tag_name: v${{ github.run_number }} name: Release v${{ github.run_number }} diff --git a/.github/workflows/clone-tracking.yml b/.github/workflows/clone-tracking.yml index 79483c78..8975fa7b 100644 --- a/.github/workflows/clone-tracking.yml +++ b/.github/workflows/clone-tracking.yml @@ -34,7 +34,7 @@ jobs: snapshot: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive diff --git a/.github/workflows/cog-ha-matter-release.yml b/.github/workflows/cog-ha-matter-release.yml index c4e9f051..36f587ee 100644 --- a/.github/workflows/cog-ha-matter-release.yml +++ b/.github/workflows/cog-ha-matter-release.yml @@ -27,17 +27,17 @@ jobs: name: Build x86_64 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: targets: x86_64-unknown-linux-gnu - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry @@ -66,7 +66,7 @@ jobs: echo "Signed cog-ha-matter-x86_64 ($(wc -c < dist/cog-ha-matter-x86_64.sig) bytes)" - name: Upload workflow artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: cog-ha-matter-x86_64 path: | @@ -79,12 +79,12 @@ jobs: name: Build aarch64 (arm) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: targets: aarch64-unknown-linux-gnu @@ -94,7 +94,7 @@ jobs: sudo apt-get install -y gcc-aarch64-linux-gnu - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry @@ -130,7 +130,7 @@ jobs: echo "Signed cog-ha-matter-arm ($(wc -c < dist/cog-ha-matter-arm.sig) bytes)" - name: Upload workflow artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: cog-ha-matter-arm path: | @@ -148,29 +148,29 @@ jobs: github.event_name == 'push' && vars.HAS_GCP_CREDENTIALS == 'true' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Download x86_64 artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: cog-ha-matter-x86_64 path: dist/ - name: Download arm artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: cog-ha-matter-arm path: dist/ - name: Auth to GCP - uses: google-github-actions/auth@v2 + uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed with: credentials_json: ${{ secrets.GCP_CREDENTIALS }} - name: Set up gcloud - uses: google-github-actions/setup-gcloud@v2 + uses: google-github-actions/setup-gcloud@e427ad8a34f8676edf47cf7d7925499adf3eb74f - name: Upload binaries + sidecars run: | diff --git a/.github/workflows/dashboard-a11y.yml b/.github/workflows/dashboard-a11y.yml index d171863e..e2d8906b 100644 --- a/.github/workflows/dashboard-a11y.yml +++ b/.github/workflows/dashboard-a11y.yml @@ -19,11 +19,11 @@ jobs: a11y: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: { targets: wasm32-unknown-unknown } - name: Install wasm-pack @@ -36,7 +36,7 @@ jobs: --out-dir ../../dashboard/public/nvsim-pkg \ --release -- --no-default-features --features wasm - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 with: { node-version: 20, cache: npm, cache-dependency-path: dashboard/package-lock.json } - working-directory: dashboard diff --git a/.github/workflows/dashboard-pages.yml b/.github/workflows/dashboard-pages.yml index 41b187b8..9bd3779e 100644 --- a/.github/workflows/dashboard-pages.yml +++ b/.github/workflows/dashboard-pages.yml @@ -25,17 +25,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout main - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Install Rust + wasm32 target - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: targets: wasm32-unknown-unknown - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry @@ -59,7 +59,7 @@ jobs: -- --no-default-features --features wasm - name: Setup Node 20 - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 with: node-version: 20 cache: npm @@ -76,7 +76,7 @@ jobs: run: npm run build - name: Deploy to gh-pages/nvsim/ - uses: peaceiris/actions-gh-pages@v4 + uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dashboard/dist diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml index ab1f924a..d2c5320e 100644 --- a/.github/workflows/desktop-release.yml +++ b/.github/workflows/desktop-release.yml @@ -27,17 +27,17 @@ jobs: target: [aarch64-apple-darwin, x86_64-apple-darwin] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 with: node-version: '20' - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: targets: ${{ matrix.target }} @@ -74,7 +74,7 @@ jobs: zip -r "RuView-Desktop-${{ github.event.inputs.version || '0.4.0' }}-macos-${{ steps.arch.outputs.arch }}.zip" "RuView Desktop.app" - name: Upload macOS artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ruview-macos-${{ steps.arch.outputs.arch }} path: v2/target/${{ matrix.target }}/release/bundle/macos/*.zip @@ -84,17 +84,17 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 with: node-version: '20' - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Install frontend dependencies working-directory: v2/crates/wifi-densepose-desktop/ui @@ -115,13 +115,13 @@ jobs: TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - name: Upload Windows MSI artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ruview-windows-msi path: v2/target/release/bundle/msi/*.msi - name: Upload Windows NSIS artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ruview-windows-nsis path: v2/target/release/bundle/nsis/*.exe @@ -134,12 +134,12 @@ jobs: contents: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: path: artifacts @@ -147,7 +147,7 @@ jobs: run: find artifacts -type f - name: Create or Update Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 with: name: RuView Desktop v${{ github.event.inputs.version || '0.4.0' }} tag_name: ${{ github.event.inputs.attach_to_existing || format('desktop-v{0}', github.event.inputs.version || '0.4.0') }} diff --git a/.github/workflows/firmware-ci.yml b/.github/workflows/firmware-ci.yml index 57730feb..04f3ec53 100644 --- a/.github/workflows/firmware-ci.yml +++ b/.github/workflows/firmware-ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest if: github.ref_type == 'tag' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Check firmware version.txt == tag @@ -75,7 +75,7 @@ jobs: artifact_pt: partition-table-c6.bin steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -175,7 +175,7 @@ jobs: echo "See: https://github.com/espressif/qemu/wiki" - name: Upload firmware artifact (${{ matrix.variant }}) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: esp32-csi-node-firmware-${{ matrix.variant }} path: firmware/esp32-csi-node/release-staging/ diff --git a/.github/workflows/firmware-qemu.yml b/.github/workflows/firmware-qemu.yml index 5fe26bf6..1c295760 100644 --- a/.github/workflows/firmware-qemu.yml +++ b/.github/workflows/firmware-qemu.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Cache QEMU build id: cache-qemu - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: /opt/qemu-esp32 # Include date component so cache refreshes monthly when branch updates @@ -73,7 +73,7 @@ jobs: echo "QEMU binary size: $(file_size /opt/qemu-esp32/bin/qemu-system-xtensa) bytes" - name: Upload QEMU artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: qemu-esp32 path: /opt/qemu-esp32/ @@ -99,12 +99,12 @@ jobs: - boundary-min steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Download QEMU artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: qemu-esp32 path: /opt/qemu-esp32 @@ -203,7 +203,7 @@ jobs: - name: Upload test logs if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: qemu-logs-${{ matrix.nvs_config }} path: | @@ -215,7 +215,7 @@ jobs: name: Fuzz Testing (ADR-061 Layer 6) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -253,7 +253,7 @@ jobs: - name: Upload fuzz artifacts if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: fuzz-crashes path: | @@ -266,7 +266,7 @@ jobs: name: NVS Matrix Generation runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -322,12 +322,12 @@ jobs: image: espressif/idf:v5.4 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Download QEMU artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: qemu-esp32 path: /opt/qemu-esp32 @@ -370,7 +370,7 @@ jobs: - name: Upload swarm results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: swarm-results path: | diff --git a/.github/workflows/fix-regression-guard.yml b/.github/workflows/fix-regression-guard.yml index 854f216a..742d911d 100644 --- a/.github/workflows/fix-regression-guard.yml +++ b/.github/workflows/fix-regression-guard.yml @@ -21,11 +21,11 @@ jobs: name: Verify fix markers runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - - uses: actions/setup-python@v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: '3.11' @@ -49,7 +49,7 @@ jobs: - name: Upload result artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: fix-markers-result path: fix-markers-result.json diff --git a/.github/workflows/mqtt-integration.yml b/.github/workflows/mqtt-integration.yml index 059f4cf0..aefb1a86 100644 --- a/.github/workflows/mqtt-integration.yml +++ b/.github/workflows/mqtt-integration.yml @@ -40,7 +40,7 @@ jobs: RUST_BACKTRACE: 1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -70,12 +70,12 @@ jobs: exit 1 - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: toolchain: stable - name: Cache cargo registry + build - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with: workspaces: v2 -> target diff --git a/.github/workflows/nvsim-server-docker.yml b/.github/workflows/nvsim-server-docker.yml index 3548858c..5bf33402 100644 --- a/.github/workflows/nvsim-server-docker.yml +++ b/.github/workflows/nvsim-server-docker.yml @@ -25,13 +25,13 @@ jobs: build-and-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - - uses: docker/login-action@v3 + - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 with: registry: ghcr.io username: ${{ github.actor }} @@ -39,7 +39,7 @@ jobs: - name: Extract metadata id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 with: images: ghcr.io/ruvnet/nvsim-server tags: | @@ -49,7 +49,7 @@ jobs: type=raw,value=latest,enable={{is_default_branch}} - name: Build + push - uses: docker/build-push-action@v7 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a with: context: v2 file: v2/crates/nvsim-server/Dockerfile diff --git a/.github/workflows/pip-release.yml b/.github/workflows/pip-release.yml index 782f9b34..367c23ba 100644 --- a/.github/workflows/pip-release.yml +++ b/.github/workflows/pip-release.yml @@ -90,19 +90,19 @@ jobs: arch: AMD64 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive # Linux aarch64 needs QEMU for cross-build on x86_64 runners. - name: Set up QEMU if: matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64' - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # ADR-117 §5.4: abi3-py310 — one binary per OS/arch covers all # Python minor versions ≥ 3.10. Build only cp310 wheels. - name: Build wheels (cibuildwheel) - uses: pypa/cibuildwheel@v2.21 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b env: CIBW_BUILD: "cp310-*" CIBW_ARCHS_LINUX: ${{ matrix.arch }} @@ -124,7 +124,7 @@ jobs: package-dir: python output-dir: wheelhouse - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: wheels-${{ matrix.os }}-${{ matrix.arch }} path: wheelhouse/*.whl @@ -137,7 +137,7 @@ jobs: startsWith(github.ref, 'refs/tags/v2.') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Install maturin @@ -145,7 +145,7 @@ jobs: - name: Build sdist working-directory: python run: maturin sdist --out ../sdist - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: sdist path: sdist/*.tar.gz @@ -158,8 +158,8 @@ jobs: startsWith(github.ref, 'refs/tags/v2.') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v6 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: '3.12' - name: Verify lock-step package versions @@ -185,7 +185,7 @@ jobs: run: | python -m pip install --upgrade pip build python -m build python/ruview-meta --outdir ruview-dist - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ruview path: ruview-dist/* @@ -202,10 +202,10 @@ jobs: startsWith(github.ref, 'refs/tags/v1.99') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - - uses: actions/setup-python@v5 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 with: python-version: '3.12' - name: Install build backend @@ -264,7 +264,7 @@ jobs: exit 1 fi echo "Tombstone wheel correctly raises ImportError with migration URL." - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: tombstone path: tombstone-dist/* @@ -288,7 +288,7 @@ jobs: ) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 - name: Enforce production witness gate if: | startsWith(github.ref, 'refs/tags/v2.') || @@ -299,7 +299,7 @@ jobs: exit 1 } - name: Gather all artifacts into dist/ - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: path: dist-staging - name: Flatten artifacts @@ -311,7 +311,7 @@ jobs: # before replacing `password:` with the OIDC id-token permission. - name: Publish to TestPyPI (dry-run target) if: github.event_name == 'workflow_dispatch' && inputs.publish_to == 'testpypi' - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 with: repository-url: https://test.pypi.org/legacy/ password: ${{ secrets.TESTPYPI_API_TOKEN }} @@ -321,7 +321,7 @@ jobs: if: | startsWith(github.ref, 'refs/tags/v2.') || (github.event_name == 'workflow_dispatch' && inputs.publish_to == 'pypi') - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 with: password: ${{ secrets.PYPI_API_TOKEN }} packages-dir: dist @@ -339,7 +339,7 @@ jobs: ) runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: tombstone path: dist @@ -347,7 +347,7 @@ jobs: # before replacing `password:` with the OIDC id-token permission. - name: Publish to TestPyPI (dry-run target) if: github.event_name == 'workflow_dispatch' && inputs.publish_to == 'testpypi' - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 with: repository-url: https://test.pypi.org/legacy/ password: ${{ secrets.TESTPYPI_API_TOKEN }} @@ -357,7 +357,7 @@ jobs: if: | startsWith(github.ref, 'refs/tags/v1.99') || (github.event_name == 'workflow_dispatch' && inputs.publish_to == 'pypi') - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 with: password: ${{ secrets.PYPI_API_TOKEN }} packages-dir: dist diff --git a/.github/workflows/pointcloud-pages.yml b/.github/workflows/pointcloud-pages.yml index c025d440..b364d6a1 100644 --- a/.github/workflows/pointcloud-pages.yml +++ b/.github/workflows/pointcloud-pages.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout main - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -63,7 +63,7 @@ jobs: EOF - name: Deploy to gh-pages/pointcloud/ - uses: peaceiris/actions-gh-pages@v4 + uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./_site/pointcloud diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 2993649a..39a91be4 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -68,7 +68,7 @@ jobs: name: Wheel + parity tests (features=sota) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: # The python/ crate path-deps v2/crates/* and (transitively via # train) the vendored ruvector submodule — recursive checkout keeps @@ -76,15 +76,15 @@ jobs: submodules: recursive - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: '3.11' - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Cache cargo (Swatinem/rust-cache) - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with: workspaces: | v2 @@ -133,20 +133,20 @@ jobs: name: Default wheel <= 5 MiB (ADR-117 §5.4) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: '3.11' - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Cache cargo (Swatinem/rust-cache) - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with: workspaces: python diff --git a/.github/workflows/ruview-swarm-ci.yml b/.github/workflows/ruview-swarm-ci.yml index b8074d69..bd3ca1b4 100644 --- a/.github/workflows/ruview-swarm-ci.yml +++ b/.github/workflows/ruview-swarm-ci.yml @@ -39,12 +39,12 @@ jobs: - { label: 'ruflo', flags: '--features ruflo' } - { label: 'full+train', flags: '--features full,train' } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Cache cargo - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry @@ -61,7 +61,7 @@ jobs: name: clippy (-D warnings, --no-deps) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive # v2/rust-toolchain.toml pins channel "1.89" with profile "minimal" (no @@ -69,12 +69,12 @@ jobs: # toolchain, but the override makes cargo use the separate "1.89" # toolchain — so `cargo clippy` errors "cargo-clippy is not installed for # 1.89". Install clippy on the pinned toolchain that cargo actually uses. - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: toolchain: "1.89" components: clippy - name: Cache cargo - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry @@ -96,12 +96,12 @@ jobs: name: build train_marl bin runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 - name: Cache cargo - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: | ~/.cargo/registry @@ -132,7 +132,7 @@ jobs: name: ITAR / publish guard runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: publish = false is present (no accidental crates.io publish) diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index d7cdc7b2..deedcc53 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -26,14 +26,13 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: - submodules: recursive fetch-depth: 0 - name: Set up Python continue-on-error: true - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' @@ -47,15 +46,18 @@ jobs: - name: Run Bandit security scan run: | - # The Python codebase lives under archive/v1/src (it moved there when - # the runtime was rewritten in Rust). Scanning `src/` matched nothing, - # so this SAST step was a silent no-op. - bandit -r archive/v1/src/ -f sarif -o bandit-results.sarif + # archive/v1 is frozen research code and is not shipped. Scan the + # maintained Python packages and operator scripts instead. + # Keep the Security tab actionable: publish high-severity findings. + # Medium/low findings are reviewed during focused local audits. + bandit -lll -r python/ scripts/ firmware/esp32-csi-node/ aether-arena/ \ + -x '*/tests/*,*/test/*,*/test_*.py,*/bench/*' \ + -f sarif -o bandit-results.sarif continue-on-error: true - name: Upload Bandit results to GitHub Security continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 # v3 if: always() with: sarif_file: bandit-results.sarif @@ -74,12 +76,16 @@ jobs: semgrep \ --config=p/security-audit --config=p/secrets --config=p/python \ --config=p/docker --config=p/kubernetes \ - --sarif --output=semgrep.sarif archive/v1/src/ + --severity=ERROR \ + --exclude='**/tests/**' --exclude='**/test/**' \ + --exclude='**/test_*.py' --exclude='**/bench/**' \ + --sarif --output=semgrep.sarif \ + python/ scripts/ firmware/esp32-csi-node/ aether-arena/ continue-on-error: true - name: Upload Semgrep results to GitHub Security continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 # v3 if: always() with: sarif_file: semgrep.sarif @@ -97,13 +103,11 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 - with: - submodules: recursive + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Set up Python continue-on-error: true - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' @@ -135,7 +139,7 @@ jobs: - name: Upload Snyk results to GitHub Security continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 # v3 if: always() with: sarif_file: snyk-results.sarif @@ -143,7 +147,7 @@ jobs: - name: Upload vulnerability reports continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: vulnerability-reports @@ -157,7 +161,6 @@ jobs: name: Container Security Scan runs-on: ubuntu-latest continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR - needs: [] if: github.event_name == 'push' || github.event_name == 'schedule' permissions: security-events: write @@ -166,20 +169,20 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: submodules: recursive - name: Set up Docker Buildx continue-on-error: true - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Build Docker image for scanning continue-on-error: true - uses: docker/build-push-action@v7 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 with: context: . - target: production + file: docker/Dockerfile.rust load: true tags: wifi-densepose:scan cache-from: type=gha @@ -192,50 +195,21 @@ jobs: image-ref: 'wifi-densepose:scan' format: 'sarif' output: 'trivy-results.sarif' + severity: 'CRITICAL,HIGH' + ignore-unfixed: true + limit-severities-for-sarif: true - name: Upload Trivy results to GitHub Security continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 # v3 if: always() with: sarif_file: 'trivy-results.sarif' category: trivy - - name: Run Grype vulnerability scanner - continue-on-error: true - uses: anchore/scan-action@v7 - id: grype-scan - with: - image: 'wifi-densepose:scan' - fail-build: false - severity-cutoff: high - output-format: sarif - - - name: Upload Grype results to GitHub Security - continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 - if: always() - with: - sarif_file: ${{ steps.grype-scan.outputs.sarif }} - category: grype - - - name: Run Docker Scout - continue-on-error: true - uses: docker/scout-action@v1 - if: always() - with: - command: cves - image: wifi-densepose:scan - sarif-file: scout-results.sarif - summary: true - - - name: Upload Docker Scout results - continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 - if: always() - with: - sarif_file: scout-results.sarif - category: docker-scout + # Trivy is the single container SARIF authority. Grype and Docker Scout + # produced duplicate alerts for the same image packages and obscured the + # actionable high/critical findings. # Infrastructure as Code security scanning iac-scan: @@ -249,52 +223,25 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Run Checkov IaC scan - continue-on-error: true - uses: bridgecrewio/checkov-action@99bb2caf247dfd9f03cf984373bc6043d4e32ebf # v12.1347.0 - with: - directory: . - framework: kubernetes,dockerfile,terraform,ansible - output_format: sarif - output_file_path: checkov-results.sarif - quiet: true - soft_fail: true - - - name: Upload Checkov results to GitHub Security - continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 - if: always() - with: - sarif_file: checkov-results.sarif - category: checkov - - - name: Run Terrascan IaC scan - continue-on-error: true - uses: tenable/terrascan-action@3a6e87da8e244513bd77b631e624552643f794c6 # v1.4.1 - with: - iac_type: 'k8s' - iac_version: 'v1' - policy_type: 'k8s' - only_warn: true - sarif_upload: true + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Run KICS IaC scan continue-on-error: true uses: checkmarx/kics-github-action@05aa5eb70eede1355220f4ca5238d96b397e30a6 # v2.1.20 with: - path: '.' + # Scan RuView-owned operational IaC only. Submodules are audited and + # fixed in their owning repositories; archived/benchmark fixtures are + # intentionally not production infrastructure. + path: '.github/workflows,docker,logging,v2/crates/nvsim-server/Dockerfile' output_path: kics-results output_formats: 'sarif' exclude_paths: '.git,node_modules' exclude_queries: 'a7ef1e8c-fbf8-4ac1-b8c7-2c3b0e6c6c6c' + exclude_severities: 'info' - name: Upload KICS results to GitHub Security continue-on-error: true - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 # v3 if: always() with: sarif_file: kics-results/results.sarif @@ -312,9 +259,8 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: - submodules: recursive fetch-depth: 0 - name: Run TruffleHog secret scan @@ -328,7 +274,7 @@ jobs: - name: Run GitLeaks secret scan continue-on-error: true - uses: gitleaks/gitleaks-action@v2 + uses: gitleaks/gitleaks-action@dcedce43c6f43de0b836d1fe38946645c9c638dc # v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} @@ -348,13 +294,11 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 - with: - submodules: recursive + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Set up Python continue-on-error: true - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' @@ -374,7 +318,7 @@ jobs: - name: Upload license report continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: license-report path: licenses.json @@ -387,9 +331,7 @@ jobs: steps: - name: Checkout code continue-on-error: true - uses: actions/checkout@v4 - with: - submodules: recursive + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Check security policy files continue-on-error: true @@ -444,7 +386,7 @@ jobs: steps: - name: Download all artifacts continue-on-error: true - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 - name: Generate security summary continue-on-error: true @@ -464,7 +406,7 @@ jobs: - name: Upload security summary continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: security-summary path: security-summary.md @@ -475,7 +417,7 @@ jobs: - name: Notify security team on critical findings continue-on-error: true if: ${{ env.SECURITY_SLACK_WEBHOOK_URL != '' && (needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure' || needs.container-scan.result == 'failure') }} - uses: 8398a7/action-slack@v3 + uses: 8398a7/action-slack@77eaa4f1c608a7d68b38af4e3f739dcd8cba273e # v3 with: status: failure channel: '#security' @@ -491,7 +433,7 @@ jobs: - name: Create security issue on critical findings continue-on-error: true if: needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure' - uses: actions/github-script@v6 + uses: actions/github-script@00f12e3e20659f42342b1c0226afda7f7c042325 # v6 with: script: | github.rest.issues.create({ @@ -518,4 +460,4 @@ jobs: **Security Dashboard:** Check the Security tab for detailed findings. `, labels: ['security', 'vulnerability', 'urgent'] - }) \ No newline at end of file + }) diff --git a/.github/workflows/semconv.yml b/.github/workflows/semconv.yml index 880b8490..1780ea7d 100644 --- a/.github/workflows/semconv.yml +++ b/.github/workflows/semconv.yml @@ -32,10 +32,10 @@ jobs: WEAVER_SHA256: a9822c712d6871bd89d6530f18c5df5cea3821f642e7b8e5e49e985917f7d12d steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: persist-credentials: false - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: components: rustfmt - name: Install weaver diff --git a/.github/workflows/sensing-server-docker.yml b/.github/workflows/sensing-server-docker.yml index 9a876c4f..0338b455 100644 --- a/.github/workflows/sensing-server-docker.yml +++ b/.github/workflows/sensing-server-docker.yml @@ -48,7 +48,7 @@ jobs: name: build · push · smoke-test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -56,9 +56,9 @@ jobs: # 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-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - name: Log in to Docker Hub # Bypassing docker/login-action@v3: the action kept emitting @@ -73,7 +73,7 @@ jobs: printf '%s' "$DH_TOKEN" | docker login docker.io -u "$DH_USER" --password-stdin - name: Log in to ghcr.io - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 with: registry: ghcr.io username: ${{ github.actor }} @@ -81,7 +81,7 @@ jobs: - name: Compute tags id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 with: images: | docker.io/ruvnet/wifi-densepose @@ -94,7 +94,7 @@ jobs: - name: Build + push id: build - uses: docker/build-push-action@v7 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a with: context: . file: docker/Dockerfile.rust diff --git a/.github/workflows/threejs-pages.yml b/.github/workflows/threejs-pages.yml index d3a51c23..46413d4b 100644 --- a/.github/workflows/threejs-pages.yml +++ b/.github/workflows/threejs-pages.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout main - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive @@ -62,7 +62,7 @@ jobs: ls -R _site/three.js/ | head -30 - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: _site diff --git a/.github/workflows/update-submodules.yml b/.github/workflows/update-submodules.yml index 99f55a3e..f57e19dc 100644 --- a/.github/workflows/update-submodules.yml +++ b/.github/workflows/update-submodules.yml @@ -13,7 +13,7 @@ jobs: update: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: true fetch-depth: 0 diff --git a/.github/workflows/verify-pipeline.yml b/.github/workflows/verify-pipeline.yml index 6a1f3ed5..3de3786c 100644 --- a/.github/workflows/verify-pipeline.yml +++ b/.github/workflows/verify-pipeline.yml @@ -29,12 +29,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: submodules: recursive - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 with: python-version: ${{ matrix.python-version }} diff --git a/aether-arena/calibration/calibrate.py b/aether-arena/calibration/calibrate.py index 31ed08ec..571d4e83 100644 --- a/aether-arena/calibration/calibrate.py +++ b/aether-arena/calibration/calibrate.py @@ -36,7 +36,10 @@ def main(): dev = a.device net = PoseNet().to(dev) - net.load_state_dict(torch.load(a.base, map_location=dev), strict=False) + # Checkpoints are tensor state dictionaries; never invoke pickle object loading. + net.load_state_dict( + torch.load(a.base, map_location=dev, weights_only=True), strict=False + ) net.add_lora(r=a.rank).to(dev) for k, p in net.named_parameters(): p.requires_grad = k.endswith(".A") or k.endswith(".B") diff --git a/aether-arena/calibration/infer.py b/aether-arena/calibration/infer.py index 2d5deb79..ee2b3864 100644 --- a/aether-arena/calibration/infer.py +++ b/aether-arena/calibration/infer.py @@ -25,7 +25,10 @@ def main(): dev = a.device net = PoseNet().to(dev) - net.load_state_dict(torch.load(a.base, map_location=dev), strict=False) + # Checkpoints are tensor state dictionaries; never invoke pickle object loading. + net.load_state_dict( + torch.load(a.base, map_location=dev, weights_only=True), strict=False + ) if a.adapter: net.add_lora(r=a.rank).to(dev) z = np.load(a.adapter) diff --git a/docker/Dockerfile.rust b/docker/Dockerfile.rust index 1332a0ae..d1b366b6 100644 --- a/docker/Dockerfile.rust +++ b/docker/Dockerfile.rust @@ -75,8 +75,6 @@ RUN set -e; \ # Optional bearer-token auth on /api/v1/*: leave unset for LAN-mode (default), # set to enforce `Authorization: Bearer ` (see bearer_auth module, #443). # docker run -e RUVIEW_API_TOKEN=$(openssl rand -hex 32) ... -ENV RUVIEW_API_TOKEN= - # HTTP API EXPOSE 3000 # WebSocket diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f7dcf273..f45f3d78 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,14 +1,14 @@ -version: "3.9" - services: sensing-server: build: context: .. dockerfile: docker/Dockerfile.rust image: ruvnet/wifi-densepose:latest + # ESP32 CSI must accept LAN UDP; TCP APIs below remain loopback-only. + # kics-scan ignore-line ports: - - "3000:3000" # REST API - - "3001:3001" # WebSocket + - "127.0.0.1:3000:3000" # REST API + - "127.0.0.1:3001:3001" # WebSocket # ESP32 UDP. On Linux/macOS this works with multiple ESP32 nodes out of # the box. On Docker Desktop for Windows, multi-source UDP is collapsed # to one source IP at the WSL/Hyper-V boundary, so all-but-one node's @@ -37,6 +37,20 @@ services: # volumes: ["/path/to/models:/app/models"] # MODELS_DIR=/app/models - MODELS_DIR=${MODELS_DIR:-data/models} + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "2.0" + memory: 1G + healthcheck: + test: ["CMD-SHELL", "kill -0 1"] + interval: 30s + timeout: 3s + retries: 3 # No explicit command needed — docker-entrypoint.sh uses CSI_SOURCE. # Override with: command: ["--source", "esp32", "--tick-ms", "500"] @@ -46,7 +60,21 @@ services: dockerfile: docker/Dockerfile.python image: ruvnet/wifi-densepose:python ports: - - "8765:8765" # WebSocket - - "8080:8080" # UI + - "127.0.0.1:8765:8765" # WebSocket + - "127.0.0.1:8080:8080" # UI environment: - PYTHONUNBUFFERED=1 + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "1.0" + memory: 512M + healthcheck: + test: ["CMD", "python", "-c", "import socket; socket.create_connection(('127.0.0.1', 8765), 2).close()"] + interval: 30s + timeout: 3s + retries: 3 diff --git a/docker/otel-compose.yml b/docker/otel-compose.yml index cd8fe388..a64df6e6 100644 --- a/docker/otel-compose.yml +++ b/docker/otel-compose.yml @@ -18,9 +18,11 @@ services: # only activates when OTEL_EXPORTER_OTLP_ENDPOINT is set. SENSING_FEATURES: mqtt,otel image: ruvnet/wifi-densepose:otel + # ESP32 CSI must accept LAN UDP; TCP APIs below remain loopback-only. + # kics-scan ignore-line ports: - - "3000:3000" # REST API - - "3001:3001" # WebSocket + - "127.0.0.1:3000:3000" # REST API + - "127.0.0.1:3001:3001" # WebSocket - "5005:5005/udp" # ESP32 CSI (see docker-compose.yml for Windows notes) environment: - RUST_LOG=info @@ -30,6 +32,20 @@ services: - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 depends_on: - otel-collector + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "2.0" + memory: 1G + healthcheck: + test: ["CMD-SHELL", "kill -0 1"] + interval: 30s + timeout: 3s + retries: 3 otel-collector: image: otel/opentelemetry-collector-contrib:0.116.0@sha256:70217a89d27c678ead44f196d80aa8c2717cb68d0301dbdc40331dbec0a3e605 @@ -37,10 +53,24 @@ services: volumes: - ./otel-collector.yaml:/etc/otelcol-contrib/config.yaml:ro ports: - - "4317:4317" # OTLP gRPC (also reachable from the host) - - "4318:4318" # OTLP HTTP + - "127.0.0.1:4317:4317" # OTLP gRPC (also reachable from the host) + - "127.0.0.1:4318:4318" # OTLP HTTP depends_on: - ourios + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "1.0" + memory: 512M + healthcheck: + test: ["CMD-SHELL", "kill -0 1"] + interval: 30s + timeout: 3s + retries: 3 # Ourios — OTLP-native log backend (Parquet + Drain-derived template # mining + DataFusion). Local-disk storage; the tenant derives from the @@ -57,10 +87,24 @@ services: - OURIOS_QUERIER_ENABLED=1 - OURIOS_QUERIER_HTTP_ADDR=0.0.0.0:4319 ports: - - "4319:4319" # query endpoint (http://localhost:4319/v1/query) + - "127.0.0.1:4319:4319" # query endpoint (http://localhost:4319/v1/query) volumes: - ourios-data:/data - ourios-wal:/wal + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "2.0" + memory: 2G + healthcheck: + test: ["CMD-SHELL", "kill -0 1"] + interval: 30s + timeout: 3s + retries: 3 volumes: ourios-data: diff --git a/firmware/esp32-csi-node/main/c6_softap_he.c b/firmware/esp32-csi-node/main/c6_softap_he.c index 7cde16f9..1cac6830 100644 --- a/firmware/esp32-csi-node/main/c6_softap_he.c +++ b/firmware/esp32-csi-node/main/c6_softap_he.c @@ -123,7 +123,7 @@ esp_err_t c6_softap_he_start(uint8_t *out_channel) if (ssid_len > 32) ssid_len = 32; memcpy(ap_cfg.ap.ssid, ssid, ssid_len); ap_cfg.ap.ssid_len = (uint8_t)ssid_len; - strncpy((char *)ap_cfg.ap.password, psk, sizeof(ap_cfg.ap.password) - 1); + strlcpy((char *)ap_cfg.ap.password, psk, sizeof(ap_cfg.ap.password)); ap_cfg.ap.channel = s_channel; ap_cfg.ap.max_connection = 4; ap_cfg.ap.authmode = strlen(psk) >= 8 ? WIFI_AUTH_WPA2_PSK : WIFI_AUTH_OPEN; diff --git a/firmware/esp32-csi-node/main/main.c b/firmware/esp32-csi-node/main/main.c index 6627bbbb..6991efe6 100644 --- a/firmware/esp32-csi-node/main/main.c +++ b/firmware/esp32-csi-node/main/main.c @@ -112,8 +112,10 @@ static void wifi_init_sta(void) }; /* Copy runtime SSID/password from NVS config */ - strncpy((char *)wifi_config.sta.ssid, g_nvs_config.wifi_ssid, sizeof(wifi_config.sta.ssid) - 1); - strncpy((char *)wifi_config.sta.password, g_nvs_config.wifi_password, sizeof(wifi_config.sta.password) - 1); + strlcpy((char *)wifi_config.sta.ssid, g_nvs_config.wifi_ssid, + sizeof(wifi_config.sta.ssid)); + strlcpy((char *)wifi_config.sta.password, g_nvs_config.wifi_password, + sizeof(wifi_config.sta.password)); /* If password is empty, use open auth */ if (strlen((char *)wifi_config.sta.password) == 0) { @@ -431,9 +433,12 @@ void app_main(void) .ingest_sec = g_nvs_config.swarm_ingest_sec, .enabled = 1, }; - strncpy(swarm_cfg.seed_url, g_nvs_config.seed_url, sizeof(swarm_cfg.seed_url) - 1); - strncpy(swarm_cfg.seed_token, g_nvs_config.seed_token, sizeof(swarm_cfg.seed_token) - 1); - strncpy(swarm_cfg.zone_name, g_nvs_config.zone_name, sizeof(swarm_cfg.zone_name) - 1); + strlcpy(swarm_cfg.seed_url, g_nvs_config.seed_url, + sizeof(swarm_cfg.seed_url)); + strlcpy(swarm_cfg.seed_token, g_nvs_config.seed_token, + sizeof(swarm_cfg.seed_token)); + strlcpy(swarm_cfg.zone_name, g_nvs_config.zone_name, + sizeof(swarm_cfg.zone_name)); swarm_ret = swarm_bridge_init(&swarm_cfg, csi_collector_get_node_id()); if (swarm_ret != ESP_OK) { ESP_LOGW(TAG, "Swarm bridge init failed: %s", esp_err_to_name(swarm_ret)); diff --git a/firmware/esp32-csi-node/main/nvs_config.c b/firmware/esp32-csi-node/main/nvs_config.c index c0fe09d0..dd4517ef 100644 --- a/firmware/esp32-csi-node/main/nvs_config.c +++ b/firmware/esp32-csi-node/main/nvs_config.c @@ -24,18 +24,16 @@ void nvs_config_load(nvs_config_t *cfg) } /* Start with Kconfig compiled defaults */ - strncpy(cfg->wifi_ssid, CONFIG_CSI_WIFI_SSID, NVS_CFG_SSID_MAX - 1); - cfg->wifi_ssid[NVS_CFG_SSID_MAX - 1] = '\0'; + strlcpy(cfg->wifi_ssid, CONFIG_CSI_WIFI_SSID, sizeof(cfg->wifi_ssid)); #ifdef CONFIG_CSI_WIFI_PASSWORD - strncpy(cfg->wifi_password, CONFIG_CSI_WIFI_PASSWORD, NVS_CFG_PASS_MAX - 1); - cfg->wifi_password[NVS_CFG_PASS_MAX - 1] = '\0'; + strlcpy(cfg->wifi_password, CONFIG_CSI_WIFI_PASSWORD, + sizeof(cfg->wifi_password)); #else cfg->wifi_password[0] = '\0'; #endif - strncpy(cfg->target_ip, CONFIG_CSI_TARGET_IP, NVS_CFG_IP_MAX - 1); - cfg->target_ip[NVS_CFG_IP_MAX - 1] = '\0'; + strlcpy(cfg->target_ip, CONFIG_CSI_TARGET_IP, sizeof(cfg->target_ip)); cfg->target_port = (uint16_t)CONFIG_CSI_TARGET_PORT; cfg->node_id = (uint8_t)CONFIG_CSI_NODE_ID; @@ -110,24 +108,21 @@ void nvs_config_load(nvs_config_t *cfg) /* WiFi SSID */ len = sizeof(buf); if (nvs_get_str(handle, "ssid", buf, &len) == ESP_OK && len > 1) { - strncpy(cfg->wifi_ssid, buf, NVS_CFG_SSID_MAX - 1); - cfg->wifi_ssid[NVS_CFG_SSID_MAX - 1] = '\0'; + strlcpy(cfg->wifi_ssid, buf, sizeof(cfg->wifi_ssid)); ESP_LOGI(TAG, "NVS override: ssid=%s", cfg->wifi_ssid); } /* WiFi password */ len = sizeof(buf); if (nvs_get_str(handle, "password", buf, &len) == ESP_OK) { - strncpy(cfg->wifi_password, buf, NVS_CFG_PASS_MAX - 1); - cfg->wifi_password[NVS_CFG_PASS_MAX - 1] = '\0'; + strlcpy(cfg->wifi_password, buf, sizeof(cfg->wifi_password)); ESP_LOGI(TAG, "NVS override: password=***"); } /* Target IP */ len = sizeof(buf); if (nvs_get_str(handle, "target_ip", buf, &len) == ESP_OK && len > 1) { - strncpy(cfg->target_ip, buf, NVS_CFG_IP_MAX - 1); - cfg->target_ip[NVS_CFG_IP_MAX - 1] = '\0'; + strlcpy(cfg->target_ip, buf, sizeof(cfg->target_ip)); ESP_LOGI(TAG, "NVS override: target_ip=%s", cfg->target_ip); } @@ -313,7 +308,7 @@ void nvs_config_load(nvs_config_t *cfg) } len = sizeof(cfg->zone_name); if (nvs_get_str(handle, "zone_name", cfg->zone_name, &len) != ESP_OK) { - strncpy(cfg->zone_name, "default", sizeof(cfg->zone_name) - 1); + strlcpy(cfg->zone_name, "default", sizeof(cfg->zone_name)); } if (nvs_get_u16(handle, "swarm_hb", &cfg->swarm_heartbeat_sec) != ESP_OK) { cfg->swarm_heartbeat_sec = 30; diff --git a/firmware/esp32-csi-node/main/wasm_runtime.c b/firmware/esp32-csi-node/main/wasm_runtime.c index 8696be9f..289206b9 100644 --- a/firmware/esp32-csi-node/main/wasm_runtime.c +++ b/firmware/esp32-csi-node/main/wasm_runtime.c @@ -786,8 +786,7 @@ esp_err_t wasm_runtime_set_manifest(uint8_t module_id, const char *module_name, } if (module_name) { - strncpy(slot->module_name, module_name, 31); - slot->module_name[31] = '\0'; + strlcpy(slot->module_name, module_name, sizeof(slot->module_name)); } slot->capabilities = capabilities; slot->manifest_budget_us = max_frame_us; diff --git a/firmware/esp32-csi-node/main/wasm_upload.c b/firmware/esp32-csi-node/main/wasm_upload.c index 66a7ec2f..565e0595 100644 --- a/firmware/esp32-csi-node/main/wasm_upload.c +++ b/firmware/esp32-csi-node/main/wasm_upload.c @@ -183,7 +183,9 @@ static esp_err_t wasm_upload_handler(httpd_req_t *req) #else format = "raw"; err = wasm_runtime_load(buf, (uint32_t)total, &module_id); - free(buf); + /* CONFIG_WASM_SKIP_SIGNATURE makes this and the reject branch above + * mutually exclusive, so the raw payload is released exactly once. */ + free(buf); /* nosemgrep: c.lang.security.double-free.double-free */ if (err != ESP_OK) { char msg[80]; diff --git a/firmware/esp32-csi-node/provision.py b/firmware/esp32-csi-node/provision.py index d87ccd04..88172fe4 100644 --- a/firmware/esp32-csi-node/provision.py +++ b/firmware/esp32-csi-node/provision.py @@ -264,7 +264,9 @@ def generate_nvs_binary(csv_content, size): gen_script = os.path.join(idf_path, "components", "nvs_flash", "nvs_partition_generator", "nvs_partition_gen.py") if os.path.isfile(gen_script): - subprocess.check_call([ + # Fixed interpreter/script plus an argv list (never a shell); + # csv_path/bin_path are private NamedTemporaryFile paths. + subprocess.check_call([ # nosemgrep: dangerous-subprocess-use-tainted-env-args sys.executable, gen_script, "generate", csv_path, bin_path, hex(size) ]) diff --git a/logging/fluentd-config.yml b/logging/fluentd-config.yml index 5596f738..e150e58e 100644 --- a/logging/fluentd-config.yml +++ b/logging/fluentd-config.yml @@ -1,11 +1,44 @@ # Fluentd Configuration for WiFi-DensePose # This configuration sets up comprehensive log aggregation and processing +apiVersion: v1 +kind: Namespace +metadata: + name: logging +--- +apiVersion: v1 +kind: ResourceQuota +metadata: + name: logging-quota + namespace: logging +spec: + hard: + pods: "500" + requests.cpu: "100" + requests.memory: 200Gi + limits.cpu: "200" + limits.memory: 400Gi +--- +apiVersion: v1 +kind: LimitRange +metadata: + name: logging-defaults + namespace: logging +spec: + limits: + - type: Container + defaultRequest: + cpu: 100m + memory: 256Mi + default: + cpu: 200m + memory: 512Mi +--- apiVersion: v1 kind: ConfigMap metadata: name: fluentd-config - namespace: kube-system + namespace: logging labels: app: fluentd component: logging @@ -453,7 +486,7 @@ apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd - namespace: kube-system + namespace: logging labels: app: fluentd component: logging @@ -467,19 +500,37 @@ spec: app: fluentd component: logging annotations: + container.apparmor.security.beta.kubernetes.io/fluentd: runtime/default prometheus.io/scrape: "true" prometheus.io/port: "24231" prometheus.io/path: "/metrics" spec: serviceAccountName: fluentd + # Required for Kubernetes metadata enrichment; the bound ClusterRole is + # read-only and limited to pods and namespaces. + # kics-scan ignore-line + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule - key: node-role.kubernetes.io/control-plane effect: NoSchedule containers: + # Fluentd needs root to read node-owned container logs. Privilege + # escalation and Linux capabilities remain disabled below. + # kics-scan ignore-line - name: fluentd - image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch7-1 + image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch7-1@sha256:4f148ebcf8a90b4f54897931f214cf6b7bb27177fb184ece558d7efb13041c0d + imagePullPolicy: Always + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL env: - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch.logging.svc.cluster.local" @@ -518,6 +569,8 @@ spec: mountPath: /fluentd/etc - name: fluentd-buffer mountPath: /var/log/fluentd-buffers + - name: fluentd-tmp + mountPath: /tmp ports: - containerPort: 24231 name: prometheus @@ -538,24 +591,32 @@ spec: volumes: - name: varlog hostPath: + # Required input for a node-level log collector. + # kics-scan ignore-line path: /var/log - name: varlibdockercontainers hostPath: + # Required input for a node-level log collector. + # kics-scan ignore-line path: /var/lib/docker/containers - name: fluentd-config configMap: name: fluentd-config - name: fluentd-buffer hostPath: + # Persistent buffer survives Fluentd pod restarts. + # kics-scan ignore-line path: /var/log/fluentd-buffers type: DirectoryOrCreate + - name: fluentd-tmp + emptyDir: {} --- apiVersion: v1 kind: ServiceAccount metadata: name: fluentd - namespace: kube-system + namespace: logging labels: app: fluentd @@ -591,14 +652,14 @@ roleRef: subjects: - kind: ServiceAccount name: fluentd - namespace: kube-system + namespace: logging --- apiVersion: v1 kind: Service metadata: name: fluentd - namespace: kube-system + namespace: logging labels: app: fluentd component: logging @@ -614,4 +675,4 @@ spec: port: 24231 targetPort: 24231 protocol: TCP - type: ClusterIP \ No newline at end of file + type: ClusterIP diff --git a/scripts/generate_nvs_matrix.py b/scripts/generate_nvs_matrix.py index 5713fa4c..53a6b63e 100644 --- a/scripts/generate_nvs_matrix.py +++ b/scripts/generate_nvs_matrix.py @@ -317,7 +317,9 @@ def generate_nvs_binary(csv_content: str, size: int) -> bytes: "nvs_partition_generator", "nvs_partition_gen.py" ) if os.path.isfile(gen_script): - subprocess.check_call([ + # Fixed interpreter/script plus an argv list (never a shell); + # csv_path/bin_path are private NamedTemporaryFile paths. + subprocess.check_call([ # nosemgrep: dangerous-subprocess-use-tainted-env-args sys.executable, gen_script, "generate", csv_path, bin_path, hex(size) ]) diff --git a/scripts/occworld_retrain.py b/scripts/occworld_retrain.py index 7c81323e..4cfd549c 100644 --- a/scripts/occworld_retrain.py +++ b/scripts/occworld_retrain.py @@ -187,7 +187,10 @@ def cmd_transformer(args: argparse.Namespace) -> None: # Load VQVAE checkpoint if provided if args.vqvae_checkpoint: - ck = torch.load(args.vqvae_checkpoint, map_location="cuda") + # VQ-VAE checkpoints contain tensors/state dictionaries only. + ck = torch.load( + args.vqvae_checkpoint, map_location="cuda", weights_only=True + ) full_model.vae.load_state_dict(ck["state_dict"]) log.info("Loaded VQVAE checkpoint: %s", args.vqvae_checkpoint) full_model.vae.eval() diff --git a/scripts/occworld_server.py b/scripts/occworld_server.py index 909b5bfe..a356699c 100644 --- a/scripts/occworld_server.py +++ b/scripts/occworld_server.py @@ -198,7 +198,8 @@ def load_model(checkpoint_path: str | None = None) -> Any: if checkpoint_path and os.path.isfile(checkpoint_path): log.info("Loading checkpoint: %s", checkpoint_path) - ckpt = torch.load(checkpoint_path, map_location="cpu") + # OccWorld checkpoints contain tensors/state dictionaries only. + ckpt = torch.load(checkpoint_path, map_location="cpu", weights_only=True) state = ckpt.get("state_dict", ckpt) # Strip common "model." prefix from distributed training saves state = {k.removeprefix("model."): v for k, v in state.items()} diff --git a/scripts/provision.py b/scripts/provision.py index 3222bf10..a26d664d 100644 --- a/scripts/provision.py +++ b/scripts/provision.py @@ -103,7 +103,9 @@ def generate_nvs_binary(csv_content, size): gen_script = os.path.join(idf_path, "components", "nvs_flash", "nvs_partition_generator", "nvs_partition_gen.py") if os.path.isfile(gen_script): - subprocess.check_call([ + # Fixed interpreter/script plus an argv list (never a shell); + # csv_path/bin_path are private NamedTemporaryFile paths. + subprocess.check_call([ # nosemgrep: dangerous-subprocess-use-tainted-env-args sys.executable, gen_script, "generate", csv_path, bin_path, hex(size) ]) diff --git a/v2/crates/nvsim-server/Dockerfile b/v2/crates/nvsim-server/Dockerfile index ca149b51..05fc67c4 100644 --- a/v2/crates/nvsim-server/Dockerfile +++ b/v2/crates/nvsim-server/Dockerfile @@ -6,8 +6,11 @@ # Run: # docker run --rm -p 7878:7878 nvsim-server:latest -FROM rust:1.81-slim-bookworm AS builder +FROM rust:1.81-slim-bookworm@sha256:f9fb6bdb0483de4ade93b262a3f6cf8c2985fca1d34784914bbcabd5a34d3197 AS builder WORKDIR /build +# Debian security revisions intentionally float within the immutable base +# snapshot so rebuilds receive patched packages without brittle version pins. +# kics-scan ignore-line RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config libssl-dev ca-certificates \ && rm -rf /var/lib/apt/lists/* @@ -46,7 +49,10 @@ EOF RUN cargo build --release -p nvsim-server --bin nvsim-server -FROM debian:bookworm-slim +FROM debian:bookworm-slim@sha256:7b140f374b289a7c2befc338f42ebe6441b7ea838a042bbd5acbfca6ec875818 +# Debian security revisions intentionally float within the immutable base +# snapshot so rebuilds receive patched packages without brittle version pins. +# kics-scan ignore-line RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates curl \ && rm -rf /var/lib/apt/lists/* \ diff --git a/vendor/metaharness b/vendor/metaharness index 87b6c517..18a82b3d 160000 --- a/vendor/metaharness +++ b/vendor/metaharness @@ -1 +1 @@ -Subproject commit 87b6c517c7e6bb021762b002bfa54c4f5b4acd65 +Subproject commit 18a82b3ddd22b7d99868acfcf7fa8164243d59b1 diff --git a/vendor/midstream b/vendor/midstream index 92250c20..583b32ef 160000 --- a/vendor/midstream +++ b/vendor/midstream @@ -1 +1 @@ -Subproject commit 92250c20d8aa3d867fcc8cb75aeabbc95eb1a0cc +Subproject commit 583b32ef35dfdb60c7d3d5c28c68f1f635b55b21 diff --git a/vendor/rufield b/vendor/rufield index e65c90d1..43b1df3d 160000 --- a/vendor/rufield +++ b/vendor/rufield @@ -1 +1 @@ -Subproject commit e65c90d1b41f581cccd79539adeea1f0f4cea38c +Subproject commit 43b1df3dc3c436a21e3fc85dc34475458a1eca9d diff --git a/vendor/ruvector b/vendor/ruvector index f3de1724..3472db77 160000 --- a/vendor/ruvector +++ b/vendor/ruvector @@ -1 +1 @@ -Subproject commit f3de1724fa5d8ff871ac24a528575f115b2a9df7 +Subproject commit 3472db77831a9943d800ed853a0d167109227d49 diff --git a/vendor/rvcsi b/vendor/rvcsi index 77c8b6e0..2ef4fd1e 160000 --- a/vendor/rvcsi +++ b/vendor/rvcsi @@ -1 +1 @@ -Subproject commit 77c8b6e051fe8a2a3370715d4c3139311b93c364 +Subproject commit 2ef4fd1e3a30dad68cb7969135a809a0ef230656 diff --git a/vendor/sublinear-time-solver b/vendor/sublinear-time-solver index 47804fc5..6ef45761 160000 --- a/vendor/sublinear-time-solver +++ b/vendor/sublinear-time-solver @@ -1 +1 @@ -Subproject commit 47804fc5ca495d4fd608866fdb1e0960b34bffbf +Subproject commit 6ef45761e9a27029cf968322b3967364499e3b5d