Consolidate GitHub Actions CI from 15 to 5 workflow files

Reduce Docker builds from 10 to 1 per PR by building the image once and
sharing it as an artifact across all dependent jobs. Merge duplicate
Docker Hub and GHCR push workflows into single workflows that push to
both registries per build.

- ci.yml: replaces pre-commit, rust_tests, validate_plano_config,
  plano_tools_tests, docker-security-scan, e2e_tests, e2e_plano_tests,
  e2e_test_preference_based_routing, e2e_test_currency_convert
- docker-push-main.yml: replaces old docker-push-main + ghrc-push-main
- docker-push-release.yml: replaces old docker-push-release + ghrc-push-release
- static.yml and publish-pypi.yml unchanged

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Adil Hafeez 2026-02-15 02:15:23 +00:00
parent ef285f1213
commit ea78102b89
14 changed files with 564 additions and 778 deletions

480
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,480 @@
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
security-events: write
env:
PLANO_DOCKER_IMAGE: katanemo/plano:e2e
DOCKER_IMAGE: katanemo/plano
jobs:
# ──────────────────────────────────────────────
# Pre-commit (fmt, clippy, cargo test, black, yaml)
# ──────────────────────────────────────────────
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: pre-commit/action@v3.0.1
# ──────────────────────────────────────────────
# Plano tools (CLI) tests — no Docker needed
# ──────────────────────────────────────────────
plano-tools-tests:
runs-on: ubuntu-latest-m
defaults:
run:
working-directory: ./cli
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Install plano tools
run: uv sync --extra dev
- name: Run tests
run: uv run pytest
# ──────────────────────────────────────────────
# Single Docker build — shared by all downstream jobs
# ──────────────────────────────────────────────
docker-build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build plano image (with GHA cache)
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
load: true
tags: |
${{ env.PLANO_DOCKER_IMAGE }}
${{ env.DOCKER_IMAGE }}:0.4.6
${{ env.DOCKER_IMAGE }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Save image as artifact
run: docker save ${{ env.PLANO_DOCKER_IMAGE }} ${{ env.DOCKER_IMAGE }}:0.4.6 ${{ env.DOCKER_IMAGE }}:latest -o /tmp/plano-image.tar
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: plano-image
path: /tmp/plano-image.tar
retention-days: 1
# ──────────────────────────────────────────────
# Validate plano config
# ──────────────────────────────────────────────
validate-config:
needs: docker-build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Validate plano config
run: bash config/validate_plano_config.sh
# ──────────────────────────────────────────────
# Docker security scan (Trivy)
# ──────────────────────────────────────────────
security-scan:
needs: docker-build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.DOCKER_IMAGE }}:latest
format: table
exit-code: ${{ github.event_name == 'pull_request' && '1' || '0' }}
ignore-unfixed: true
severity: CRITICAL,HIGH
- name: Run Trivy scanner (SARIF for GitHub Security tab)
if: always()
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.DOCKER_IMAGE }}:latest
format: sarif
output: trivy-results.sarif
ignore-unfixed: true
severity: CRITICAL,HIGH
- name: Upload Trivy results to GitHub Security tab
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
# ──────────────────────────────────────────────
# E2E: prompt_gateway tests
# ──────────────────────────────────────────────
test-prompt-gateway:
needs: docker-build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
- name: Run prompt_gateway tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
GROK_API_KEY: ${{ secrets.GROK_API_KEY }}
run: |
cd tests/e2e && bash run_prompt_gateway_tests.sh
# ──────────────────────────────────────────────
# E2E: model_alias_routing tests
# ──────────────────────────────────────────────
test-model-alias-routing:
needs: docker-build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
- name: Run model alias routing tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
GROK_API_KEY: ${{ secrets.GROK_API_KEY }}
run: |
cd tests/e2e && bash run_model_alias_tests.sh
# ──────────────────────────────────────────────
# E2E: responses API with state tests
# ──────────────────────────────────────────────
test-responses-api-with-state:
needs: docker-build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
- name: Run responses API with state tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
GROK_API_KEY: ${{ secrets.GROK_API_KEY }}
run: |
cd tests/e2e && bash run_responses_state_tests.sh
# ──────────────────────────────────────────────
# E2E: plano tests (multi-Python matrix)
# ──────────────────────────────────────────────
e2e-plano-tests:
needs: docker-build
runs-on: ubuntu-latest-m
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
defaults:
run:
working-directory: ./tests/archgw
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Start plano
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
run: |
docker compose up | tee &> plano.logs &
- name: Wait for plano to be healthy
run: |
source common.sh && wait_for_healthz http://localhost:10000/healthz
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Install test dependencies
run: uv sync
- name: Run plano tests
run: |
uv run pytest || tail -100 plano.logs
- name: Stop plano docker container
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
docker compose down
# ──────────────────────────────────────────────
# E2E: demo — preference based routing
# ──────────────────────────────────────────────
e2e-demo-preference:
needs: docker-build
runs-on: ubuntu-latest-m
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Setup python venv
run: python -m venv venv
- name: Install hurl
run: |
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
sudo dpkg -i hurl_4.0.0_amd64.deb
- name: Install plano gateway and test dependencies
run: |
source venv/bin/activate
cd cli && echo "installing plano cli" && uv sync && uv tool install .
cd ../demos/shared/test_runner && echo "installing test dependencies" && uv sync
- name: Run demo tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ARCH_API_KEY: ${{ secrets.ARCH_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
source venv/bin/activate
cd demos/shared/test_runner && sh run_demo_tests.sh use_cases/preference_based_routing
# ──────────────────────────────────────────────
# E2E: demo — currency conversion
# ──────────────────────────────────────────────
e2e-demo-currency:
needs: docker-build
runs-on: ubuntu-latest-m
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Setup python venv
run: python -m venv venv
- name: Install hurl
run: |
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
sudo dpkg -i hurl_4.0.0_amd64.deb
- name: Install plano gateway and test dependencies
run: |
source venv/bin/activate
cd cli && echo "installing plano cli" && uv sync && uv tool install .
cd ../demos/shared/test_runner && echo "installing test dependencies" && uv sync
- name: Run demo tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
run: |
source venv/bin/activate
cd demos/shared/test_runner && sh run_demo_tests.sh samples_python/currency_exchange

View file

@ -2,6 +2,7 @@ name: Publish docker image (latest)
env:
DOCKER_IMAGE: katanemo/plano
GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/plano
on:
push:
@ -10,9 +11,10 @@ on:
permissions:
contents: read
packages: write
jobs:
# Build ARM64 image on native ARM64 runner.
# Build ARM64 image on native ARM64 runner — push to both registries
build-arm64:
runs-on: [linux-arm64]
steps:
@ -25,13 +27,12 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
- name: Log in to GHCR
uses: docker/login-action@v3
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=latest # Force the tag to be "latest"
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push ARM64 Image
uses: docker/build-push-action@v5
@ -40,9 +41,11 @@ jobs:
file: ./Dockerfile
platforms: linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}-arm64
tags: |
${{ env.DOCKER_IMAGE }}:latest-arm64
${{ env.GHCR_IMAGE }}:latest-arm64
# Build AMD64 image on GitHub's AMD64 runner
# Build AMD64 image on GitHub's AMD64 runner — push to both registries
build-amd64:
runs-on: ubuntu-latest
steps:
@ -55,13 +58,12 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
- name: Log in to GHCR
uses: docker/login-action@v3
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=latest # Force the tag to be "latest"
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push AMD64 Image
uses: docker/build-push-action@v5
@ -70,13 +72,14 @@ jobs:
file: ./Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}-amd64
tags: |
${{ env.DOCKER_IMAGE }}:latest-amd64
${{ env.GHCR_IMAGE }}:latest-amd64
# Combine ARM64 and AMD64 images into a multi-arch manifest
# Combine ARM64 and AMD64 images into multi-arch manifests for both registries
create-manifest:
runs-on: ubuntu-latest
needs: [build-arm64, build-amd64] # Wait for both builds
needs: [build-arm64, build-amd64]
steps:
- name: Log in to Docker Hub
uses: docker/login-action@v3
@ -84,17 +87,23 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
- name: Log in to GHCR
uses: docker/login-action@v3
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=latest # Force the tag to be "latest"
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create Multi-Arch Manifest
- name: Create Docker Hub Multi-Arch Manifest
run: |
# Combine the architecture-specific images into a "latest" manifest
docker buildx imagetools create -t ${{ steps.meta.outputs.tags }} \
docker buildx imagetools create \
-t ${{ env.DOCKER_IMAGE }}:latest \
${{ env.DOCKER_IMAGE }}:latest-arm64 \
${{ env.DOCKER_IMAGE }}:latest-amd64
- name: Create GHCR Multi-Arch Manifest
run: |
docker buildx imagetools create \
-t ${{ env.GHCR_IMAGE }}:latest \
${{ env.GHCR_IMAGE }}:latest-arm64 \
${{ env.GHCR_IMAGE }}:latest-amd64

View file

@ -2,6 +2,7 @@ name: Publish docker image (release)
env:
DOCKER_IMAGE: katanemo/plano
GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/plano
on:
release:
@ -9,9 +10,10 @@ on:
permissions:
contents: read
packages: write
jobs:
# Build ARM64 image on native ARM64 runner
# Build ARM64 image on native ARM64 runner — push to both registries
build-arm64:
runs-on: [linux-arm64]
steps:
@ -24,7 +26,14 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
@ -39,9 +48,11 @@ jobs:
file: ./Dockerfile
platforms: linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}-arm64
tags: |
${{ steps.meta.outputs.tags }}-arm64
${{ env.GHCR_IMAGE }}:${{ github.event.release.tag_name }}-arm64
# Build AMD64 image on GitHub's AMD64 runner
# Build AMD64 image on GitHub's AMD64 runner — push to both registries
build-amd64:
runs-on: ubuntu-latest
steps:
@ -54,7 +65,14 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
@ -69,12 +87,14 @@ jobs:
file: ./Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}-amd64
tags: |
${{ steps.meta.outputs.tags }}-amd64
${{ env.GHCR_IMAGE }}:${{ github.event.release.tag_name }}-amd64
# Combine ARM64 and AMD64 images into a multi-arch manifest
# Combine ARM64 and AMD64 images into multi-arch manifests for both registries
create-manifest:
runs-on: ubuntu-latest
needs: [build-arm64, build-amd64] # Wait for both builds
needs: [build-arm64, build-amd64]
steps:
- name: Log in to Docker Hub
uses: docker/login-action@v3
@ -82,7 +102,14 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
@ -90,9 +117,17 @@ jobs:
tags: |
type=raw,value={{tag}}
- name: Create Multi-Arch Manifest
- name: Create Docker Hub Multi-Arch Manifest
run: |
# Combine the architecture-specific images into a single manifest
docker buildx imagetools create -t ${{ steps.meta.outputs.tags }} \
docker buildx imagetools create \
-t ${{ steps.meta.outputs.tags }} \
${{ steps.meta.outputs.tags }}-arm64 \
${{ steps.meta.outputs.tags }}-amd64
- name: Create GHCR Multi-Arch Manifest
run: |
TAG=${{ github.event.release.tag_name }}
docker buildx imagetools create \
-t ${{ env.GHCR_IMAGE }}:${TAG} \
${{ env.GHCR_IMAGE }}:${TAG}-arm64 \
${{ env.GHCR_IMAGE }}:${TAG}-amd64

View file

@ -1,56 +0,0 @@
name: Docker Security Scan
env:
DOCKER_IMAGE: katanemo/plano
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
security-events: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Build Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: false
tags: ${{ env.DOCKER_IMAGE }}:scan
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.DOCKER_IMAGE }}:scan
format: table
# Fail on PRs so vulnerabilities block merge; on main just report
exit-code: ${{ github.event_name == 'pull_request' && '1' || '0' }}
ignore-unfixed: true
severity: CRITICAL,HIGH
- name: Run Trivy scanner (SARIF for GitHub Security tab)
if: always()
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.DOCKER_IMAGE }}:scan
format: sarif
output: trivy-results.sarif
ignore-unfixed: true
severity: CRITICAL,HIGH
- name: Upload Trivy results to GitHub Security tab
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif

View file

@ -1,72 +0,0 @@
name: e2e plano tests
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
jobs:
e2e_plano_tests:
runs-on: ubuntu-latest-m
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
defaults:
run:
working-directory: ./tests/archgw
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "pip" # auto-caches based on requirements files
- name: build plano docker image
run: |
cd ../../ && docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.6 -t katanemo/plano:latest
- name: start plano
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
run: |
docker compose up | tee &> plano.logs &
- name: wait for plano to be healthy
run: |
source common.sh && wait_for_healthz http://localhost:10000/healthz
- name: install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: install test dependencies
run: |
uv sync
- name: run plano tests
run: |
uv run pytest || tail -100 plano.logs
- name: stop plano docker container
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
docker compose down

View file

@ -1,54 +0,0 @@
name: e2e demo tests currency conversion
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
jobs:
e2e_demo_tests:
runs-on: ubuntu-latest-m
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: build plano docker image
run: |
docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.6
- name: install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: setup python venv
run: |
python -m venv venv
- name: install hurl
run: |
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
sudo dpkg -i hurl_4.0.0_amd64.deb
- name: install plano gateway and test dependencies
run: |
source venv/bin/activate
cd cli && echo "installing plano cli" && uv sync && uv tool install .
cd ../demos/shared/test_runner && echo "installing test dependencies" && uv sync
- name: run demo tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
run: |
source venv/bin/activate
cd demos/shared/test_runner && sh run_demo_tests.sh samples_python/currency_exchange

View file

@ -1,56 +0,0 @@
name: e2e demo preference based routing tests
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
jobs:
e2e_demo_tests:
runs-on: ubuntu-latest-m
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: build plano docker image
run: |
docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.6
- name: install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: setup python venv
run: |
python -m venv venv
- name: install hurl
run: |
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
sudo dpkg -i hurl_4.0.0_amd64.deb
- name: install plano gateway and test dependencies
run: |
source venv/bin/activate
cd cli && echo "installing plano cli" && uv sync && uv tool install .
cd ../demos/shared/test_runner && echo "installing test dependencies" && uv sync
- name: run demo tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ARCH_API_KEY: ${{ secrets.ARCH_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
source venv/bin/activate
cd demos/shared/test_runner && sh run_demo_tests.sh use_cases/preference_based_routing

View file

@ -1,203 +0,0 @@
name: e2e tests
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
# Shared env vars for all jobs that run tests
env:
PLANO_DOCKER_IMAGE: katanemo/plano:e2e
jobs:
# ──────────────────────────────────────────────
# Job 1: Build the Docker image once, with cache
# ──────────────────────────────────────────────
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build plano image (with GHA cache)
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
load: true
tags: ${{ env.PLANO_DOCKER_IMAGE }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Save image as artifact
run: docker save ${{ env.PLANO_DOCKER_IMAGE }} -o /tmp/plano-image.tar
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: plano-image
path: /tmp/plano-image.tar
retention-days: 1
# ──────────────────────────────────────────────
# Job 2a: prompt_gateway tests
# ──────────────────────────────────────────────
test-prompt-gateway:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
- name: Run prompt_gateway tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
GROK_API_KEY: ${{ secrets.GROK_API_KEY }}
run: |
cd tests/e2e && bash run_prompt_gateway_tests.sh
# ──────────────────────────────────────────────
# Job 2b: model_alias_routing + responses API tests
# ──────────────────────────────────────────────
test-model-alias-routing:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
- name: Run model alias routing tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
GROK_API_KEY: ${{ secrets.GROK_API_KEY }}
run: |
cd tests/e2e && bash run_model_alias_tests.sh
# ──────────────────────────────────────────────
# Job 2c: responses API with state storage tests
# ──────────────────────────────────────────────
test-responses-api-with-state:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Free disk space on runner
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
docker system prune -af || true
docker volume prune -f || true
- name: Download plano image
uses: actions/download-artifact@v4
with:
name: plano-image
path: /tmp
- name: Load plano image
run: docker load -i /tmp/plano-image.tar
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
- name: Run responses API with state tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
GROK_API_KEY: ${{ secrets.GROK_API_KEY }}
run: |
cd tests/e2e && bash run_responses_state_tests.sh

View file

@ -1,88 +0,0 @@
name: Publish docker image to ghcr (latest)
env:
IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/plano
on:
push:
branches: [main]
jobs:
build-arm64:
runs-on: [linux-arm64]
permissions: { contents: read, packages: write }
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
- name: Build and Push ARM64 Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/arm64
push: true
# produce ghcr.io/<owner>/plano:latest-arm64
tags: ${{ steps.meta.outputs.tags }}-arm64
build-amd64:
runs-on: ubuntu-latest
permissions: { contents: read, packages: write }
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
- name: Build and Push AMD64 Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}-amd64
create-manifest:
runs-on: ubuntu-latest
needs: [build-arm64, build-amd64]
permissions: { contents: read, packages: write }
steps:
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
- name: Create Multi-Arch Manifest
run: |
docker buildx imagetools create -t ${{ steps.meta.outputs.tags }} \
${{ env.IMAGE_NAME }}:latest-arm64 \
${{ env.IMAGE_NAME }}:latest-amd64

View file

@ -1,87 +0,0 @@
name: release - publish docker image to ghcr (latest)
env:
IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/plano
on:
release:
types: [published]
jobs:
build-arm64:
runs-on: [linux-arm64]
permissions: { contents: read, packages: write }
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value={{tag}}
- name: Build and Push ARM64 Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}-arm64
build-amd64:
runs-on: ubuntu-latest
permissions: { contents: read, packages: write }
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value={{tag}}
- name: Build and Push AMD64 Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}-amd64
create-manifest:
runs-on: ubuntu-latest
needs: [build-arm64, build-amd64]
permissions: { contents: read, packages: write }
steps:
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value={{tag}}
- name: Create Multi-Arch Manifest
run: |
docker buildx imagetools create -t ${{ steps.meta.outputs.tags }} \
${{ steps.meta.outputs.tags }}-arm64 \
${{ steps.meta.outputs.tags }}-amd64

View file

@ -1,37 +0,0 @@
name: plano tools tests
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
jobs:
plano_tools_tests:
runs-on: ubuntu-latest-m
defaults:
run:
working-directory: ./cli
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: install plano tools
run: |
uv sync --extra dev
- name: run tests
run: |
uv run pytest

View file

@ -1,17 +0,0 @@
name: pre-commit
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: pre-commit/action@v3.0.1

View file

@ -1,34 +0,0 @@
name: rust tests (prompt and llm gateway)
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
name: Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./crates
steps:
- name: Setup | Checkout
uses: actions/checkout@v4
- name: Setup | Rust
run: rustup toolchain install 1.92 --profile minimal
- name: Setup | Install wasm toolchain
run: rustup target add wasm32-wasip1
- name: Build wasm module
run: |
cargo build --release --target=wasm32-wasip1 -p llm_gateway -p prompt_gateway
- name: Run unit tests
run: cargo test --lib

View file

@ -1,34 +0,0 @@
name: plano config tests
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
jobs:
validate_plano_config:
runs-on: ubuntu-latest
defaults:
run:
working-directory: .
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: build plano docker image
run: |
docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.6
- name: validate plano config
run: |
bash config/validate_plano_config.sh