161ef94b4f
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge API Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge UI Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Has been cancelled
Sirius CI/CD Pipeline / Integration Test (push) Has been cancelled
Sirius CI/CD Pipeline / Public Stack Contract (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Has been cancelled
1067 lines
45 KiB
YAML
1067 lines
45 KiB
YAML
name: Sirius CI/CD Pipeline
|
|
|
|
# Canonical CI pipeline. Handles all builds, tests, and canary dispatch.
|
|
# deploy.yml is now deployment-only (workflow_dispatch) and does not build images.
|
|
#
|
|
# Multi-arch strategy: each container is built per-platform (amd64 native,
|
|
# arm64 via QEMU) on GitHub-hosted runners. After both arch builds succeed,
|
|
# arch-specific tags are merged into a single multi-arch manifest.
|
|
|
|
on:
|
|
push:
|
|
branches: [main, sirius-demo]
|
|
pull_request:
|
|
branches: [main]
|
|
repository_dispatch:
|
|
types: [submodule-update]
|
|
|
|
env:
|
|
REGISTRY: ghcr.io
|
|
IMAGE_NAMESPACE: siriusscan
|
|
|
|
jobs:
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Detect which services actually changed so we only build what's needed
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
detect-changes:
|
|
name: Detect Changes
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
sirius_ui_changes: ${{ steps.changes.outputs.sirius_ui_changes }}
|
|
sirius_api_changes: ${{ steps.changes.outputs.sirius_api_changes }}
|
|
sirius_engine_changes: ${{ steps.changes.outputs.sirius_engine_changes }}
|
|
sirius_infra_changes: ${{ steps.changes.outputs.sirius_infra_changes }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Determine Changed Files
|
|
id: changes
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
SUBMODULE="${{ github.event.client_payload.submodule }}"
|
|
echo "submodule_changes=true" >> $GITHUB_OUTPUT
|
|
echo "Submodule update detected: $SUBMODULE"
|
|
|
|
REPO_NAME=$(echo $SUBMODULE | awk -F'/' '{print $NF}')
|
|
|
|
case $REPO_NAME in
|
|
"go-api")
|
|
echo "Affects both sirius-api and sirius-engine"
|
|
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
"app-scanner"|"app-terminal"|"sirius-nse"|"app-agent")
|
|
echo "Affects sirius-engine"
|
|
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
*)
|
|
echo "Unknown submodule, rebuilding everything"
|
|
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_infra_changes=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
esac
|
|
else
|
|
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
BASE_SHA=${{ github.event.pull_request.base.sha }}
|
|
HEAD_SHA=${{ github.event.pull_request.head.sha }}
|
|
else
|
|
BASE_SHA=${{ github.event.before }}
|
|
HEAD_SHA=${{ github.event.after }}
|
|
fi
|
|
|
|
git diff --name-only $BASE_SHA $HEAD_SHA > changed_files.txt
|
|
|
|
if grep -q "sirius-ui/" changed_files.txt; then
|
|
echo "UI changes detected"
|
|
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
if grep -q "sirius-api/" changed_files.txt; then
|
|
echo "API changes detected"
|
|
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
if grep -q "sirius-engine/" changed_files.txt || grep -q "rabbitmq/" changed_files.txt; then
|
|
echo "Engine or RabbitMQ changes detected"
|
|
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
if grep -q -E "^(sirius-postgres/|sirius-rabbitmq/|sirius-valkey/|rabbitmq/)" changed_files.txt; then
|
|
echo "Infrastructure changes detected"
|
|
echo "sirius_infra_changes=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
# Dockerfile or CI changes trigger a full rebuild
|
|
if grep -q -E "(Dockerfile|\.github/|docker-compose)" changed_files.txt; then
|
|
echo "Docker or CI changes detected, rebuilding everything"
|
|
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_infra_changes=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
# No specific changes but something did change: full rebuild
|
|
if [ ! -s changed_files.txt ]; then
|
|
echo "General changes detected, rebuilding everything"
|
|
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
|
echo "sirius_infra_changes=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Guard against accidental image namespace typos in CI/build paths.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
guard-registry-namespace:
|
|
name: "Guard Registry Namespace"
|
|
needs: detect-changes
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Fail on typoed GHCR namespace
|
|
run: |
|
|
set -e
|
|
TARGETS=".github/workflows docker-compose.yaml docker-stack.swarm.yaml scripts sirius-api sirius-engine sirius-postgres sirius-rabbitmq sirius-ui sirius-valkey"
|
|
BAD_NAMESPACE="${{ env.REGISTRY }}/sirius""cam/"
|
|
if grep -R --line-number "$BAD_NAMESPACE" $TARGETS; then
|
|
echo "::error::Found typoed GHCR namespace '${BAD_NAMESPACE}'. Use '${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/'."
|
|
exit 1
|
|
fi
|
|
echo "Registry namespace guard passed."
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Build sirius-ui
|
|
# PRs build amd64 only; main/dispatch builds both arches (arm64 via QEMU).
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
build-ui:
|
|
name: "Build UI (${{ matrix.platform }})"
|
|
needs: [detect-changes, guard-registry-namespace]
|
|
if: needs.detect-changes.outputs.sirius_ui_changes == 'true'
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: ${{ github.event_name == 'pull_request' && fromJSON('["amd64"]') || fromJSON('["amd64","arm64"]') }}
|
|
|
|
steps:
|
|
- name: Checkout Sirius repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
TAG="pr-${{ github.event.number }}"
|
|
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
TAG="dev"
|
|
fi
|
|
echo "image_tag=$TAG" >> $GITHUB_OUTPUT
|
|
|
|
- name: Install UI dependencies
|
|
run: npm ci
|
|
working-directory: sirius-ui
|
|
|
|
- name: Lint UI code
|
|
continue-on-error: true
|
|
run: npm run lint
|
|
working-directory: sirius-ui
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Build and push sirius-ui (${{ matrix.platform }})
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ./sirius-ui
|
|
platforms: linux/${{ matrix.platform }}
|
|
push: true
|
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${{ steps.meta.outputs.image_tag }}-${{ matrix.platform }}
|
|
|
|
# Merge arch-specific UI images into a single multi-arch manifest
|
|
merge-ui:
|
|
name: "Merge UI Manifest"
|
|
needs: build-ui
|
|
if: needs.detect-changes.outputs.sirius_ui_changes == 'true' && github.event_name != 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
image_tag: ${{ steps.meta.outputs.image_tag }}
|
|
steps:
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "image_tag=dev" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Create and push multi-arch manifest for sirius-ui
|
|
run: |
|
|
TAG="${{ steps.meta.outputs.image_tag }}"
|
|
BASE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui"
|
|
|
|
docker buildx imagetools create -t ${BASE}:${TAG} \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
|
|
if [ "${{ steps.meta.outputs.also_tag_beta }}" == "true" ]; then
|
|
docker buildx imagetools create -t ${BASE}:beta \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
fi
|
|
|
|
echo "Published ${BASE}:${TAG} (amd64 + arm64)"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Build sirius-api
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
build-api:
|
|
name: "Build API (${{ matrix.platform }})"
|
|
needs: [detect-changes, guard-registry-namespace]
|
|
if: needs.detect-changes.outputs.sirius_api_changes == 'true'
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: ${{ github.event_name == 'pull_request' && fromJSON('["amd64"]') || fromJSON('["amd64","arm64"]') }}
|
|
|
|
steps:
|
|
- name: Checkout Sirius repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
SUBMODULE="${{ github.event.client_payload.submodule }}"
|
|
REPO_NAME=$(echo $SUBMODULE | awk -F'/' '{print $NF}')
|
|
COMMIT_SHA="${{ github.event.client_payload.commit_sha }}"
|
|
if [ "$REPO_NAME" == "go-api" ]; then
|
|
echo "GO_API_COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_ENV
|
|
fi
|
|
fi
|
|
|
|
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
TAG="pr-${{ github.event.number }}"
|
|
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
TAG="dev"
|
|
fi
|
|
echo "image_tag=$TAG" >> $GITHUB_OUTPUT
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: '1.24'
|
|
|
|
- name: Compile-check API code
|
|
run: |
|
|
go mod download
|
|
go vet ./...
|
|
working-directory: sirius-api
|
|
|
|
- name: Run API tests (non-blocking)
|
|
continue-on-error: true
|
|
run: go test ./... -short -count=1
|
|
working-directory: sirius-api
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Build and push sirius-api (${{ matrix.platform }})
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ./sirius-api
|
|
platforms: linux/${{ matrix.platform }}
|
|
push: true
|
|
# Fallback SHAs MUST match sirius-engine/Dockerfile ARG defaults.
|
|
# Enforced by .github/workflows/check-pin-consistency.yml.
|
|
build-args: |
|
|
GO_API_COMMIT_SHA=${{ env.GO_API_COMMIT_SHA || 'v0.0.18' }}
|
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${{ steps.meta.outputs.image_tag }}-${{ matrix.platform }}
|
|
|
|
# Merge arch-specific API images into a single multi-arch manifest
|
|
merge-api:
|
|
name: "Merge API Manifest"
|
|
needs: build-api
|
|
if: needs.detect-changes.outputs.sirius_api_changes == 'true' && github.event_name != 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
image_tag: ${{ steps.meta.outputs.image_tag }}
|
|
steps:
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "image_tag=dev" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Create and push multi-arch manifest for sirius-api
|
|
run: |
|
|
TAG="${{ steps.meta.outputs.image_tag }}"
|
|
BASE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api"
|
|
|
|
docker buildx imagetools create -t ${BASE}:${TAG} \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
|
|
if [ "${{ steps.meta.outputs.also_tag_beta }}" == "true" ]; then
|
|
docker buildx imagetools create -t ${BASE}:beta \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
fi
|
|
|
|
echo "Published ${BASE}:${TAG} (amd64 + arm64)"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Build sirius-engine
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
build-engine:
|
|
name: "Build Engine (${{ matrix.platform }})"
|
|
needs: [detect-changes, guard-registry-namespace]
|
|
if: needs.detect-changes.outputs.sirius_engine_changes == 'true'
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: ${{ github.event_name == 'pull_request' && fromJSON('["amd64"]') || fromJSON('["amd64","arm64"]') }}
|
|
|
|
steps:
|
|
- name: Checkout Sirius repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Generate image tag and submodule SHAs
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
SUBMODULE="${{ github.event.client_payload.submodule }}"
|
|
REPO_NAME=$(echo $SUBMODULE | awk -F'/' '{print $NF}')
|
|
COMMIT_SHA="${{ github.event.client_payload.commit_sha }}"
|
|
REPO_NAME_UPPER=$(echo $REPO_NAME | tr '-' '_' | tr 'a-z' 'A-Z')
|
|
echo "${REPO_NAME_UPPER}_COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_ENV
|
|
fi
|
|
|
|
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
TAG="pr-${{ github.event.number }}"
|
|
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
TAG="dev"
|
|
fi
|
|
echo "image_tag=$TAG" >> $GITHUB_OUTPUT
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: '1.24'
|
|
|
|
- name: Compile-check Engine code
|
|
run: |
|
|
go mod download
|
|
go vet ./...
|
|
working-directory: sirius-engine
|
|
|
|
- name: Run Engine tests (non-blocking)
|
|
continue-on-error: true
|
|
run: go test ./... -short -count=1
|
|
working-directory: sirius-engine
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Build and push sirius-engine (${{ matrix.platform }})
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ./sirius-engine
|
|
platforms: linux/${{ matrix.platform }}
|
|
push: true
|
|
# Fallback SHAs MUST match sirius-engine/Dockerfile ARG defaults.
|
|
# Floating refs (main/master) are forbidden; use a full SHA or a tag.
|
|
# Enforced by .github/workflows/check-pin-consistency.yml.
|
|
# See documentation/dev/architecture/README.engine-component-pinning.md.
|
|
build-args: |
|
|
GO_API_COMMIT_SHA=${{ env.GO_API_COMMIT_SHA || 'v0.0.18' }}
|
|
APP_SCANNER_COMMIT_SHA=${{ env.APP_SCANNER_COMMIT_SHA || 'a031480cc7e0dc4a1cb09bdcfafedd89fbc61dfd' }}
|
|
APP_TERMINAL_COMMIT_SHA=${{ env.APP_TERMINAL_COMMIT_SHA || '5745e43ca1f2ad3936a02a51cc77bfcf33ee95c1' }}
|
|
SIRIUS_NSE_COMMIT_SHA=${{ env.SIRIUS_NSE_COMMIT_SHA || 'a58e8c5330b49bd8f4e93c27e340c43c1fa89fa9' }}
|
|
APP_AGENT_COMMIT_SHA=${{ env.APP_AGENT_COMMIT_SHA || '9311f3805db9cc08740f1b588b6f3bff9191c9dd' }}
|
|
PINGPP_COMMIT_SHA=${{ env.PINGPP_COMMIT_SHA || '9508a16c40a49746feb7cab4b8c1c358246169b0' }}
|
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${{ steps.meta.outputs.image_tag }}-${{ matrix.platform }}
|
|
|
|
# Merge arch-specific Engine images into a single multi-arch manifest
|
|
merge-engine:
|
|
name: "Merge Engine Manifest"
|
|
needs: build-engine
|
|
if: needs.detect-changes.outputs.sirius_engine_changes == 'true' && github.event_name != 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
image_tag: ${{ steps.meta.outputs.image_tag }}
|
|
steps:
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "image_tag=dev" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Create and push multi-arch manifest for sirius-engine
|
|
run: |
|
|
TAG="${{ steps.meta.outputs.image_tag }}"
|
|
BASE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine"
|
|
|
|
docker buildx imagetools create -t ${BASE}:${TAG} \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
|
|
if [ "${{ steps.meta.outputs.also_tag_beta }}" == "true" ]; then
|
|
docker buildx imagetools create -t ${BASE}:beta \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
fi
|
|
|
|
echo "Published ${BASE}:${TAG} (amd64 + arm64)"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Build infrastructure images used by the default public stack.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
build-infra:
|
|
name: "Build Infra (${{ matrix.service }}, ${{ matrix.platform }})"
|
|
needs: [detect-changes, guard-registry-namespace]
|
|
if: >
|
|
needs.detect-changes.outputs.sirius_infra_changes == 'true' ||
|
|
github.event_name == 'repository_dispatch' ||
|
|
(github.event_name == 'push' && github.ref == 'refs/heads/main')
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
service: [sirius-postgres, sirius-rabbitmq, sirius-valkey]
|
|
platform: ${{ github.event_name == 'pull_request' && fromJSON('["amd64"]') || fromJSON('["amd64","arm64"]') }}
|
|
|
|
steps:
|
|
- name: Checkout Sirius repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
TAG="pr-${{ github.event.number }}"
|
|
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
TAG="latest"
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
TAG="dev"
|
|
fi
|
|
echo "image_tag=$TAG" >> $GITHUB_OUTPUT
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Build and push infra image (${{ matrix.service }}, ${{ matrix.platform }})
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ./${{ matrix.service }}
|
|
platforms: linux/${{ matrix.platform }}
|
|
push: true
|
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ matrix.service }}:${{ steps.meta.outputs.image_tag }}-${{ matrix.platform }}
|
|
|
|
merge-infra:
|
|
name: "Merge Infra Manifest (${{ matrix.service }})"
|
|
needs: [detect-changes, build-infra]
|
|
if: >
|
|
github.event_name != 'pull_request' &&
|
|
(
|
|
needs.detect-changes.outputs.sirius_infra_changes == 'true' ||
|
|
github.event_name == 'repository_dispatch' ||
|
|
(github.event_name == 'push' && github.ref == 'refs/heads/main')
|
|
)
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
service: [sirius-postgres, sirius-rabbitmq, sirius-valkey]
|
|
steps:
|
|
- name: Generate image tag
|
|
id: meta
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
echo "image_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "image_tag=dev" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Create and push multi-arch manifest for infra image
|
|
run: |
|
|
TAG="${{ steps.meta.outputs.image_tag }}"
|
|
BASE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ matrix.service }}"
|
|
|
|
docker buildx imagetools create -t ${BASE}:${TAG} \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
|
|
if [ "${{ steps.meta.outputs.also_tag_beta }}" == "true" ]; then
|
|
docker buildx imagetools create -t ${BASE}:beta \
|
|
${BASE}:${TAG}-amd64 \
|
|
${BASE}:${TAG}-arm64
|
|
fi
|
|
|
|
echo "Published ${BASE}:${TAG} (amd64 + arm64)"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Integration Test
|
|
#
|
|
# Runs after at least one service build (or merge for multi-arch) succeeds.
|
|
# Key fixes vs the previous version:
|
|
# 1. sirius-api is ALWAYS started when sirius-engine is tested, because
|
|
# start-enhanced.sh validates the API key contract at startup.
|
|
# 2. sirius-engine depends_on sirius-api in the test compose config.
|
|
# 3. The health-wait loop covers sirius-api even when only engine changed.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
test:
|
|
name: Integration Test
|
|
needs:
|
|
- detect-changes
|
|
- build-ui
|
|
- build-api
|
|
- build-engine
|
|
runs-on: ubuntu-latest
|
|
if: >
|
|
always() &&
|
|
(
|
|
needs.build-ui.result == 'success' ||
|
|
needs.build-api.result == 'success' ||
|
|
needs.build-engine.result == 'success'
|
|
)
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GHCR_PUSH_USER }}
|
|
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
|
|
|
- name: Determine image tag
|
|
id: tag
|
|
run: |
|
|
# Compute the tag the same way build jobs do (from event context).
|
|
# build-* are matrix jobs with no job-level outputs, so we cannot
|
|
# use needs.build-ui.outputs.image_tag — it is always empty.
|
|
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
TAG="pr-${{ github.event.number }}"
|
|
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
TAG="latest"
|
|
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/sirius-demo" ]; then
|
|
TAG="dev"
|
|
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
TAG="latest"
|
|
else
|
|
TAG="latest"
|
|
fi
|
|
# Integration tests always use the amd64 arch-specific image tag
|
|
echo "image_tag=${TAG}-amd64" >> $GITHUB_OUTPUT
|
|
echo "Using image tag: ${TAG}-amd64"
|
|
|
|
- name: Create test environment
|
|
run: |
|
|
cat > docker-compose.test.yml << 'EOF'
|
|
name: sirius-test
|
|
services:
|
|
sirius-postgres:
|
|
image: postgres:15-alpine
|
|
environment:
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: sirius_test
|
|
tmpfs:
|
|
- /var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
sirius-rabbitmq:
|
|
image: rabbitmq:3-management
|
|
environment:
|
|
RABBITMQ_DEFAULT_USER: guest
|
|
RABBITMQ_DEFAULT_PASS: guest
|
|
healthcheck:
|
|
test: ["CMD", "rabbitmq-diagnostics", "ping"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
sirius-valkey:
|
|
image: valkey/valkey:latest
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
sirius-ui:
|
|
image: ${SIRIUS_UI_IMAGE}
|
|
environment:
|
|
- NODE_ENV=production
|
|
- SKIP_ENV_VALIDATION=1
|
|
- DATABASE_URL=postgresql://postgres:postgres@sirius-postgres:5432/sirius_test
|
|
- NEXTAUTH_SECRET=test-secret
|
|
- INITIAL_ADMIN_PASSWORD=test-admin-password
|
|
- NEXTAUTH_URL=http://localhost:3000
|
|
- SIRIUS_API_URL=http://sirius-api:9001
|
|
- NEXT_PUBLIC_SIRIUS_API_URL=http://localhost:9001
|
|
- SIRIUS_API_KEY_FILE=/run/secrets/sirius_api_key
|
|
secrets:
|
|
- sirius_api_key
|
|
depends_on:
|
|
sirius-postgres:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -q --tries=1 -O /dev/null http://127.0.0.1:3000/"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 12
|
|
start_period: 15s
|
|
|
|
sirius-api:
|
|
image: ${SIRIUS_API_IMAGE}
|
|
environment:
|
|
- GO_ENV=production
|
|
- API_PORT=9001
|
|
- POSTGRES_HOST=sirius-postgres
|
|
- POSTGRES_USER=postgres
|
|
- POSTGRES_PASSWORD=postgres
|
|
- POSTGRES_DB=sirius_test
|
|
- POSTGRES_PORT=5432
|
|
- VALKEY_HOST=sirius-valkey
|
|
- VALKEY_PORT=6379
|
|
- RABBITMQ_URL=amqp://guest:guest@sirius-rabbitmq:5672/
|
|
- LOG_LEVEL=info
|
|
- SIRIUS_API_KEY_FILE=/run/secrets/sirius_api_key
|
|
secrets:
|
|
- sirius_api_key
|
|
depends_on:
|
|
sirius-postgres:
|
|
condition: service_healthy
|
|
sirius-rabbitmq:
|
|
condition: service_healthy
|
|
sirius-valkey:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "KEY=$(tr -d '\\r\\n' < /run/secrets/sirius_api_key); STATUS=$(curl -s -o /dev/null -w '%{http_code}' -H \"X-API-Key: $$KEY\" http://127.0.0.1:9001/host/); echo \"API health probe: $$STATUS\"; [ -n \"$$STATUS\" ] && [ \"$$STATUS\" != '000' ] && echo \"$$STATUS\" | grep -qvE '^5'"]
|
|
interval: 10s
|
|
timeout: 10s
|
|
retries: 24
|
|
start_period: 30s
|
|
|
|
sirius-engine:
|
|
image: ${SIRIUS_ENGINE_IMAGE}
|
|
environment:
|
|
- GO_ENV=production
|
|
- ENGINE_MAIN_PORT=5174
|
|
- GRPC_AGENT_PORT=50051
|
|
- POSTGRES_HOST=sirius-postgres
|
|
- POSTGRES_USER=postgres
|
|
- POSTGRES_PASSWORD=postgres
|
|
- POSTGRES_DB=sirius_test
|
|
- POSTGRES_PORT=5432
|
|
- VALKEY_HOST=sirius-valkey
|
|
- VALKEY_PORT=6379
|
|
- RABBITMQ_URL=amqp://guest:guest@sirius-rabbitmq:5672/
|
|
- LOG_LEVEL=info
|
|
- SIRIUS_API_KEY_FILE=/run/secrets/sirius_api_key
|
|
- SIRIUS_API_URL=http://sirius-api:9001
|
|
- API_BASE_URL=http://sirius-api:9001
|
|
secrets:
|
|
- sirius_api_key
|
|
depends_on:
|
|
sirius-postgres:
|
|
condition: service_healthy
|
|
sirius-rabbitmq:
|
|
condition: service_healthy
|
|
sirius-valkey:
|
|
condition: service_healthy
|
|
sirius-api:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "bash", "-c", "echo > /dev/tcp/127.0.0.1/50051"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 12
|
|
start_period: 30s
|
|
|
|
secrets:
|
|
sirius_api_key:
|
|
file: ./secrets/sirius_api_key.txt
|
|
EOF
|
|
|
|
mkdir -p secrets
|
|
printf '%s\n' 'ci-placeholder-api-key' > secrets/sirius_api_key.txt
|
|
chmod 644 secrets/sirius_api_key.txt
|
|
|
|
IMAGE_TAG="${{ steps.tag.outputs.image_tag }}"
|
|
export SIRIUS_UI_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${IMAGE_TAG}"
|
|
export SIRIUS_API_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${IMAGE_TAG}"
|
|
export SIRIUS_ENGINE_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${IMAGE_TAG}"
|
|
echo "SIRIUS_UI_IMAGE=$SIRIUS_UI_IMAGE" >> $GITHUB_ENV
|
|
echo "SIRIUS_API_IMAGE=$SIRIUS_API_IMAGE" >> $GITHUB_ENV
|
|
echo "SIRIUS_ENGINE_IMAGE=$SIRIUS_ENGINE_IMAGE" >> $GITHUB_ENV
|
|
|
|
- name: Run integration test
|
|
run: |
|
|
echo "Starting integration test..."
|
|
|
|
# 1. Infrastructure services
|
|
docker compose -f docker-compose.test.yml up -d sirius-postgres sirius-rabbitmq sirius-valkey
|
|
|
|
echo "Waiting for infrastructure services to become healthy..."
|
|
timeout 90 bash -c '
|
|
until docker compose -f docker-compose.test.yml ps --format json | \
|
|
python3 -c "
|
|
import sys, json
|
|
svcs = [json.loads(l) for l in sys.stdin if l.strip()]
|
|
infra = [s for s in svcs if s[\"Service\"] in (\"sirius-postgres\",\"sirius-rabbitmq\",\"sirius-valkey\")]
|
|
healthy = [s for s in infra if s.get(\"Health\",\"\") == \"healthy\"]
|
|
sys.exit(0 if len(healthy) == 3 else 1)
|
|
"; do sleep 3; done
|
|
'
|
|
echo "Infrastructure healthy"
|
|
|
|
# 2. Determine which application services to test.
|
|
# IMPORTANT: sirius-api must always be started alongside sirius-engine
|
|
# because start-enhanced.sh validates the API key contract at startup.
|
|
SERVICES_TO_TEST=""
|
|
API_REQUIRED=false
|
|
|
|
if [ "${{ needs.detect-changes.outputs.sirius_api_changes }}" == "true" ]; then
|
|
SERVICES_TO_TEST="$SERVICES_TO_TEST sirius-api"
|
|
API_REQUIRED=true
|
|
fi
|
|
|
|
if [ "${{ needs.detect-changes.outputs.sirius_engine_changes }}" == "true" ]; then
|
|
SERVICES_TO_TEST="$SERVICES_TO_TEST sirius-engine"
|
|
# Engine requires the API to be running for its startup preflight check
|
|
if [ "$API_REQUIRED" != "true" ]; then
|
|
SERVICES_TO_TEST="sirius-api$SERVICES_TO_TEST"
|
|
API_REQUIRED=true
|
|
echo "Adding sirius-api as required dependency for sirius-engine"
|
|
fi
|
|
fi
|
|
|
|
if [ "${{ needs.detect-changes.outputs.sirius_ui_changes }}" == "true" ]; then
|
|
SERVICES_TO_TEST="$SERVICES_TO_TEST sirius-ui"
|
|
fi
|
|
|
|
if [ -z "$SERVICES_TO_TEST" ]; then
|
|
echo "No application services to test"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Starting application services:$SERVICES_TO_TEST"
|
|
docker compose -f docker-compose.test.yml up -d $SERVICES_TO_TEST
|
|
|
|
# 3. Wait for each service to become healthy using Docker's built-in health status.
|
|
# This avoids exec-into-container quoting issues (e.g. the engine uses
|
|
# /dev/tcp which requires bash and breaks sh -c quoting).
|
|
for SVC in $SERVICES_TO_TEST; do
|
|
CONTAINER="sirius-test-${SVC}-1"
|
|
echo "Waiting for $SVC..."
|
|
timeout 180 bash -c "until [ \"\$(docker inspect --format '{{.State.Health.Status}}' ${CONTAINER} 2>/dev/null)\" = 'healthy' ]; do sleep 5; done" \
|
|
|| { echo "::error::Timeout waiting for ${SVC} to become healthy"; exit 1; }
|
|
echo "$SVC is healthy"
|
|
done
|
|
|
|
# 4. Final health assertions
|
|
echo "Service status:"
|
|
docker compose -f docker-compose.test.yml ps
|
|
|
|
echo "Running final health assertions..."
|
|
FAILED=0
|
|
for SVC in $SERVICES_TO_TEST; do
|
|
CONTAINER="sirius-test-${SVC}-1"
|
|
HEALTH=$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER" 2>/dev/null)
|
|
if [ "$HEALTH" = "healthy" ]; then
|
|
echo " $SVC passed (healthy)"
|
|
else
|
|
echo " $SVC FAILED (status: ${HEALTH:-unknown})"
|
|
FAILED=1
|
|
fi
|
|
done
|
|
|
|
if [ "$FAILED" -eq 1 ]; then
|
|
echo "::error::One or more services failed their health check"
|
|
exit 1
|
|
fi
|
|
echo "All health checks passed"
|
|
|
|
- name: Capture diagnostics on failure
|
|
if: failure()
|
|
run: |
|
|
mkdir -p ci-diagnostics
|
|
echo "=== docker compose ps ===" > ci-diagnostics/compose-status.txt
|
|
docker compose -f docker-compose.test.yml ps --format "table {{.Name}}\t{{.Service}}\t{{.Status}}\t{{.Health}}" \
|
|
>> ci-diagnostics/compose-status.txt 2>&1 || true
|
|
|
|
echo "=== sirius-engine inspect ===" > ci-diagnostics/engine-inspect.json
|
|
docker inspect sirius-test-sirius-engine-1 >> ci-diagnostics/engine-inspect.json 2>&1 || true
|
|
|
|
for SVC in sirius-engine sirius-api sirius-ui sirius-postgres sirius-rabbitmq sirius-valkey; do
|
|
echo "--- $SVC logs (last 200 lines) ---" > "ci-diagnostics/${SVC}.log"
|
|
docker compose -f docker-compose.test.yml logs --tail=200 "$SVC" \
|
|
>> "ci-diagnostics/${SVC}.log" 2>&1 || true
|
|
done
|
|
|
|
echo "::group::Compose Status"
|
|
cat ci-diagnostics/compose-status.txt
|
|
echo "::endgroup::"
|
|
echo "::group::sirius-engine logs"
|
|
cat ci-diagnostics/sirius-engine.log
|
|
echo "::endgroup::"
|
|
echo "::group::sirius-api logs"
|
|
cat ci-diagnostics/sirius-api.log
|
|
echo "::endgroup::"
|
|
|
|
- name: Upload diagnostic artifacts
|
|
if: failure()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: integration-test-diagnostics
|
|
path: ci-diagnostics/
|
|
retention-days: 7
|
|
|
|
- name: Cleanup test environment
|
|
if: always()
|
|
run: |
|
|
docker compose -f docker-compose.test.yml down --volumes --remove-orphans 2>/dev/null || true
|
|
|
|
public-stack-contract:
|
|
name: Public Stack Contract
|
|
needs:
|
|
- build-ui
|
|
- build-api
|
|
- build-engine
|
|
- build-infra
|
|
- merge-ui
|
|
- merge-api
|
|
- merge-engine
|
|
- merge-infra
|
|
- test
|
|
runs-on: ubuntu-latest
|
|
if: >
|
|
always() &&
|
|
(
|
|
github.event_name == 'repository_dispatch' ||
|
|
(github.event_name == 'push' && github.ref == 'refs/heads/main')
|
|
) &&
|
|
(needs.build-ui.result == 'success' || needs.build-ui.result == 'skipped') &&
|
|
(needs.build-api.result == 'success' || needs.build-api.result == 'skipped') &&
|
|
(needs.build-engine.result == 'success' || needs.build-engine.result == 'skipped') &&
|
|
(needs.build-infra.result == 'success' || needs.build-infra.result == 'skipped') &&
|
|
(needs.merge-ui.result == 'success' || needs.merge-ui.result == 'skipped') &&
|
|
(needs.merge-api.result == 'success' || needs.merge-api.result == 'skipped') &&
|
|
(needs.merge-engine.result == 'success' || needs.merge-engine.result == 'skipped') &&
|
|
(needs.merge-infra.result == 'success' || needs.merge-infra.result == 'skipped') &&
|
|
(needs.test.result == 'success' || needs.test.result == 'skipped')
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Validate public latest compose path
|
|
run: |
|
|
bash scripts/validate-public-compose-path.sh latest
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Dispatch to sirius-demo when sirius-demo branch is pushed
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
dispatch-demo-deployment:
|
|
name: Dispatch Demo Deployment (sirius-demo branch)
|
|
runs-on: ubuntu-latest
|
|
needs: [detect-changes, build-ui, build-api, build-engine, test]
|
|
if: >
|
|
github.ref == 'refs/heads/sirius-demo' &&
|
|
github.event_name == 'push' &&
|
|
always() &&
|
|
(needs.detect-changes.result == 'success' || needs.detect-changes.result == 'skipped') &&
|
|
(needs.build-ui.result == 'success' || needs.build-ui.result == 'skipped') &&
|
|
(needs.build-api.result == 'success' || needs.build-api.result == 'skipped') &&
|
|
(needs.build-engine.result == 'success' || needs.build-engine.result == 'skipped') &&
|
|
(needs.test.result == 'success' || needs.test.result == 'skipped')
|
|
steps:
|
|
- name: Dispatch to sirius-demo repository
|
|
uses: peter-evans/repository-dispatch@v3
|
|
with:
|
|
token: ${{ secrets.DEMO_DISPATCH_TOKEN }}
|
|
repository: SiriusScan/sirius-demo
|
|
event-type: sirius-demo-updated
|
|
client-payload: |
|
|
{
|
|
"source_repo": "${{ github.repository }}",
|
|
"source_branch": "${{ github.ref_name }}",
|
|
"source_sha": "${{ github.sha }}",
|
|
"triggered_by": "${{ github.actor }}"
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Canary dispatch to sirius-demo on every main branch push.
|
|
# Fixed: commit messages with newlines are sanitized before injection into JSON
|
|
# by using `gh api -f` flags which handle escaping correctly.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
dispatch-demo-canary:
|
|
name: Dispatch Demo Canary (main branch)
|
|
runs-on: ubuntu-latest
|
|
needs: [detect-changes, build-ui, build-api, build-engine, test]
|
|
if: >
|
|
github.ref == 'refs/heads/main' &&
|
|
github.event_name == 'push' &&
|
|
always() &&
|
|
(needs.detect-changes.result == 'success' || needs.detect-changes.result == 'skipped') &&
|
|
(needs.build-ui.result == 'success' || needs.build-ui.result == 'skipped') &&
|
|
(needs.build-api.result == 'success' || needs.build-api.result == 'skipped') &&
|
|
(needs.build-engine.result == 'success' || needs.build-engine.result == 'skipped') &&
|
|
(needs.test.result == 'success' || needs.test.result == 'skipped')
|
|
steps:
|
|
- name: Dispatch to sirius-demo repository (canary trigger)
|
|
env:
|
|
GH_TOKEN: ${{ secrets.DEMO_DISPATCH_TOKEN }}
|
|
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
|
run: |
|
|
# Sanitize: take first line only and strip characters that break JSON
|
|
SAFE_MSG=$(printf '%s' "$COMMIT_MSG" | head -1 | tr -d '"\\' | cut -c1-200)
|
|
|
|
gh api repos/SiriusScan/sirius-demo/dispatches \
|
|
--method POST \
|
|
-f event_type=sirius-main-updated \
|
|
-f "client_payload[source_repo]=${{ github.repository }}" \
|
|
-f "client_payload[source_branch]=${{ github.ref_name }}" \
|
|
-f "client_payload[source_sha]=${{ github.sha }}" \
|
|
-f "client_payload[triggered_by]=${{ github.actor }}" \
|
|
-f "client_payload[commit_message]=$SAFE_MSG" \
|
|
-f "client_payload[canary]=true"
|