feat: add ha_manage_custom_tool — sandboxed code execution escape hatch #2611
Workflow file for this run
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: PR Validation Pipeline | |
| permissions: | |
| contents: read | |
| on: | |
| pull_request: | |
| branches: [ master ] | |
| workflow_dispatch: | |
| env: | |
| PYTHON_VERSION: "3.13" | |
| UV_CACHE_DIR: /tmp/.uv-cache | |
| # renovate: datasource=docker depName=ghcr.io/home-assistant/home-assistant | |
| HA_IMAGE_GHCR: "ghcr.io/home-assistant/home-assistant:2026.4.1" | |
| jobs: | |
| lockfile: | |
| name: Check uv.lock | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.0-python3.13-trixie-slim | |
| timeout-minutes: 2 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Verify uv.lock is in sync with pyproject.toml | |
| run: uv lock --check | |
| lint: | |
| name: Ruff Lint | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.0-python3.13-trixie-slim | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run ruff check | |
| run: uv run ruff check src/ tests/ homeassistant-addon/ homeassistant-addon-webhook-proxy/ scripts/ | |
| ast-grep: | |
| name: AST Lint | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.0-python3.13-trixie-slim | |
| timeout-minutes: 2 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run ast-grep | |
| run: uv run ast-grep scan | |
| mypy: | |
| name: Mypy Type Check | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.0-python3.13-trixie-slim | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run mypy | |
| run: | | |
| uv run mypy src/ homeassistant-addon/ scripts/ | |
| uv run mypy homeassistant-addon-webhook-proxy/start.py | |
| # Fast unit tests (no Docker, no HA instance needed) | |
| unit-tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.0-python3.13-trixie-slim | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Install git for submodule checkout | |
| run: apt-get update -qq && apt-get install -y -qq git >/dev/null 2>&1 | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| - name: Install dependencies | |
| run: uv sync --all-extras --dev | |
| - name: Run unit tests | |
| run: uv run pytest tests/src/unit/ -n auto --tb=short -v | |
| # Comprehensive E2E validation for all PRs | |
| e2e-validation: | |
| name: E2E Validation (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - ubuntu-latest # Linux x64 | |
| - ubuntu-24.04-arm # Linux ARM64 | |
| include: | |
| - os: ubuntu-latest | |
| pytest_workers: 3 | |
| - os: ubuntu-24.04-arm | |
| pytest_workers: 4 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| cache-binary: true | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| - name: Set up Python | |
| run: uv python install ${{ env.PYTHON_VERSION }} | |
| - name: Install dependencies | |
| run: uv sync --all-extras --dev | |
| - name: Cache HA Docker image | |
| id: cache-ha-image | |
| uses: actions/cache@v5 | |
| with: | |
| path: /tmp/ha-image.tar | |
| key: ha-image-${{ env.HA_IMAGE_GHCR }}-${{ runner.arch }} | |
| - name: Load cached HA image | |
| if: steps.cache-ha-image.outputs.cache-hit == 'true' | |
| run: docker load -i /tmp/ha-image.tar | |
| - name: Pull HA image (GHCR → Docker Hub fallback) | |
| if: steps.cache-ha-image.outputs.cache-hit != 'true' | |
| run: | | |
| HA_VERSION="${HA_IMAGE_GHCR##*:}" | |
| HA_IMAGE_DOCKERHUB="homeassistant/home-assistant:${HA_VERSION}" | |
| for registry in "$HA_IMAGE_GHCR" "$HA_IMAGE_DOCKERHUB"; do | |
| echo "Trying $registry..." | |
| if docker pull "$registry"; then | |
| if [ "$registry" != "$HA_IMAGE_GHCR" ]; then | |
| docker tag "$registry" "$HA_IMAGE_GHCR" | |
| fi | |
| docker save "$HA_IMAGE_GHCR" -o /tmp/ha-image.tar | |
| echo "Pulled and cached from $registry" | |
| exit 0 | |
| fi | |
| echo "Failed to pull from $registry, trying next..." | |
| sleep 15 | |
| done | |
| echo "All registries failed" && exit 1 | |
| - name: Run full E2E test suite | |
| run: | | |
| echo "🚀 Running full E2E test suite with ${{ matrix.pytest_workers }} workers..." | |
| uv run pytest tests/src/e2e/ \ | |
| -n${{ matrix.pytest_workers }} \ | |
| --tb=short \ | |
| -v | |
| echo "✅ Full E2E test suite passed" | |
| env: | |
| HAMCP_ENV_FILE: "tests/.env.test" | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Docker and Add-on validation | |
| docker-validation: | |
| name: Docker & Add-on Validation | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| cache-binary: true | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| - name: Set up Python | |
| run: uv python install ${{ env.PYTHON_VERSION }} | |
| - name: Install test dependencies | |
| run: uv sync --dev | |
| - name: Run add-on tests | |
| run: uv run pytest tests/addon/ --ignore=tests/addon/test_skills_config.py --tb=short -v | |
| - name: Validate docker-compose configuration | |
| run: uv run pytest tests/test_docker/test_docker_compose.py -v | |
| - name: Build and test standalone Docker image | |
| run: uv run pytest tests/test_docker/test_docker_build.py -v |