mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-01 14:59:19 +08:00
0191a614b6
* feat(presidio): build & own combined analyzer+anonymizer image Replace the stock mcr.microsoft.com/presidio-* sidecar images with a single image we build and push to ECR/GHCR. A thin FastAPI service constructs one AnalyzerEngine + one AnonymizerEngine at startup and serves both on port 3000 (/health, /supportedentities, /analyze, /anonymize) so the app needs one PRESIDIO_URL. English only; pinned presidio 2.2.362 + en_core_web_lg 3.8.0. Bakes in the native check-digit VIN recognizer and registers 12 English recognizers Presidio ships but does not load by default (UK_NINO, AU_*, IN_*, SG_*), taking the supported English set from 19 to 32. * feat(presidio): add multi-language support (es/it/pl/fi) Configure a multi-language spaCy NLP engine (en/es/it/pl/fi lg models) and explicitly register the national-id recognizers Presidio ships but does not load by default: ES_NIF/NIE, IT_FISCAL_CODE/DRIVER_LICENSE/VAT_CODE/PASSPORT/ IDENTITY_CARD, PL_PESEL, FI_PERSONAL_IDENTITY_CODE. Verified the NLP-engine + explicit-registration path detects in-language (Finnish id, score 1.0). * improvement(presidio): address review feedback - Register VIN under all served languages, not just en (Bugbot: VIN missed for non-English language routing). - Bump HEALTHCHECK start-period to 180s — five lg models load at import (Bugbot). - Drop --no-cache-dir so the pip cache mount actually works (Greptile). - Pydantic request models for /analyze + /anonymize so missing 'text' returns 422 not 500; default operator 'type' to 'replace' instead of KeyError->500 (Greptile). * refactor(pii): rename presidio image artifacts to pii Rename the image/repo/secret/files from 'presidio' to 'pii' for clarity — the service does PII detection + anonymization (and backs the guardrails block's block/mask), not just redaction, and 'pii' matches existing pii-* naming. docker/presidio.Dockerfile -> docker/pii.Dockerfile docker/presidio/ -> docker/pii/ ghcr.io/simstudioai/presidio -> .../pii ECR_PRESIDIO secret -> ECR_PII (infra side already renamed) No behavior change — paths/identifiers only. * refactor(pii): move service to apps/pii, make image ECR-only - Move server.py + requirements.txt from docker/pii/ to apps/pii/ (source belongs under apps/, matching app/realtime; Dockerfile stays in docker/). Add a minimal @sim/pii package.json so the apps/* bun workspace glob accepts the Python service. - Repoint docker/pii.Dockerfile COPY paths to apps/pii/; rename the container user presidio -> pii. - Drop GHCR for pii — it's a private ECS sidecar pulled from ECR, never published. Removed it from the arm64/manifest (GHCR-only) jobs and guarded the build-amd64 tag step to skip GHCR when no ghcr_image is set.
404 lines
15 KiB
YAML
404 lines
15 KiB
YAML
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main, staging, dev]
|
||
pull_request:
|
||
branches: [main, staging, dev]
|
||
|
||
concurrency:
|
||
group: ci-${{ github.ref }}
|
||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
jobs:
|
||
test-build:
|
||
name: Test and Build
|
||
if: github.ref != 'refs/heads/dev' || github.event_name == 'pull_request'
|
||
uses: ./.github/workflows/test-build.yml
|
||
secrets: inherit
|
||
|
||
# Detect if this is a version release commit (e.g., "v0.5.24: ...")
|
||
detect-version:
|
||
name: Detect Version
|
||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/dev')
|
||
outputs:
|
||
version: ${{ steps.extract.outputs.version }}
|
||
is_release: ${{ steps.extract.outputs.is_release }}
|
||
steps:
|
||
- name: Extract version from commit message
|
||
id: extract
|
||
env:
|
||
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
||
run: |
|
||
# Only tag versions on main branch
|
||
if [ "$GITHUB_REF" = "refs/heads/main" ] && [[ "$COMMIT_MSG" =~ ^(v[0-9]+\.[0-9]+\.[0-9]+): ]]; then
|
||
VERSION="${BASH_REMATCH[1]}"
|
||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||
echo "is_release=true" >> $GITHUB_OUTPUT
|
||
echo "✅ Detected release commit: ${VERSION}"
|
||
else
|
||
echo "version=" >> $GITHUB_OUTPUT
|
||
echo "is_release=false" >> $GITHUB_OUTPUT
|
||
echo "ℹ️ Not a release commit"
|
||
fi
|
||
|
||
# Run database migrations before images are pushed: the ECR push triggers
|
||
# CodePipeline, so migrating first guarantees the schema is in place before
|
||
# the new app version deploys (replaces the removed ECS migration sidecar)
|
||
migrate:
|
||
name: Migrate DB
|
||
needs: [test-build]
|
||
if: >-
|
||
github.event_name == 'push' &&
|
||
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||
uses: ./.github/workflows/migrations.yml
|
||
with:
|
||
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
|
||
secrets: inherit
|
||
|
||
# Same ordering for dev (schema push before the dev image lands in ECR)
|
||
migrate-dev:
|
||
name: Migrate Dev DB
|
||
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
|
||
uses: ./.github/workflows/migrations.yml
|
||
with:
|
||
environment: dev
|
||
secrets: inherit
|
||
|
||
# Dev: build all 3 images for ECR only (no GHCR, no ARM64)
|
||
build-dev:
|
||
name: Build Dev ECR
|
||
needs: [detect-version, migrate-dev]
|
||
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
|
||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||
permissions:
|
||
contents: read
|
||
id-token: write
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
- dockerfile: ./docker/app.Dockerfile
|
||
ecr_repo_secret: ECR_APP
|
||
- dockerfile: ./docker/db.Dockerfile
|
||
ecr_repo_secret: ECR_MIGRATIONS
|
||
- dockerfile: ./docker/realtime.Dockerfile
|
||
ecr_repo_secret: ECR_REALTIME
|
||
- dockerfile: ./docker/pii.Dockerfile
|
||
ecr_repo_secret: ECR_PII
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||
|
||
- name: Configure AWS credentials
|
||
uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6
|
||
with:
|
||
role-to-assume: ${{ secrets.DEV_AWS_ROLE_TO_ASSUME }}
|
||
aws-region: ${{ secrets.DEV_AWS_REGION }}
|
||
|
||
- name: Login to Amazon ECR
|
||
id: login-ecr
|
||
uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2
|
||
|
||
- name: Login to Docker Hub
|
||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||
with:
|
||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
|
||
|
||
- name: Resolve ECR repo name
|
||
id: ecr-repo
|
||
run: echo "name=$ECR_REPO" >> $GITHUB_OUTPUT
|
||
env:
|
||
ECR_REPO: ${{ matrix.ecr_repo_secret == 'ECR_APP' && secrets.ECR_APP || matrix.ecr_repo_secret == 'ECR_MIGRATIONS' && secrets.ECR_MIGRATIONS || matrix.ecr_repo_secret == 'ECR_REALTIME' && secrets.ECR_REALTIME || matrix.ecr_repo_secret == 'ECR_PII' && secrets.ECR_PII || '' }}
|
||
|
||
- name: Build and push
|
||
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
|
||
with:
|
||
context: .
|
||
file: ${{ matrix.dockerfile }}
|
||
platforms: linux/amd64
|
||
push: true
|
||
tags: ${{ steps.login-ecr.outputs.registry }}/${{ steps.ecr-repo.outputs.name }}:dev
|
||
provenance: false
|
||
sbom: false
|
||
|
||
# Main/staging: build AMD64 images and push to ECR + GHCR
|
||
build-amd64:
|
||
name: Build AMD64
|
||
needs: [test-build, detect-version, migrate]
|
||
if: >-
|
||
github.event_name == 'push' &&
|
||
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
id-token: write
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
- dockerfile: ./docker/app.Dockerfile
|
||
ghcr_image: ghcr.io/simstudioai/simstudio
|
||
ecr_repo_secret: ECR_APP
|
||
- dockerfile: ./docker/db.Dockerfile
|
||
ghcr_image: ghcr.io/simstudioai/migrations
|
||
ecr_repo_secret: ECR_MIGRATIONS
|
||
- dockerfile: ./docker/realtime.Dockerfile
|
||
ghcr_image: ghcr.io/simstudioai/realtime
|
||
ecr_repo_secret: ECR_REALTIME
|
||
# pii is ECR-only (private ECS sidecar) — no ghcr_image, so the tag
|
||
# step below skips GHCR for it.
|
||
- dockerfile: ./docker/pii.Dockerfile
|
||
ecr_repo_secret: ECR_PII
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||
|
||
- name: Configure AWS credentials
|
||
uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6
|
||
with:
|
||
role-to-assume: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
|
||
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_AWS_REGION }}
|
||
|
||
- name: Login to Amazon ECR
|
||
id: login-ecr
|
||
uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2
|
||
|
||
- name: Login to Docker Hub
|
||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||
with:
|
||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||
|
||
- name: Login to GHCR
|
||
if: github.ref == 'refs/heads/main'
|
||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.repository_owner }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
|
||
|
||
- name: Resolve ECR repo name
|
||
id: ecr-repo
|
||
run: echo "name=$ECR_REPO" >> $GITHUB_OUTPUT
|
||
env:
|
||
ECR_REPO: ${{ matrix.ecr_repo_secret == 'ECR_APP' && secrets.ECR_APP || matrix.ecr_repo_secret == 'ECR_MIGRATIONS' && secrets.ECR_MIGRATIONS || matrix.ecr_repo_secret == 'ECR_REALTIME' && secrets.ECR_REALTIME || matrix.ecr_repo_secret == 'ECR_PII' && secrets.ECR_PII || '' }}
|
||
|
||
- name: Generate tags
|
||
id: meta
|
||
run: |
|
||
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
|
||
ECR_REPO="${{ steps.ecr-repo.outputs.name }}"
|
||
GHCR_IMAGE="${{ matrix.ghcr_image }}"
|
||
|
||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||
ECR_TAG="latest"
|
||
else
|
||
ECR_TAG="staging"
|
||
fi
|
||
ECR_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:${ECR_TAG}"
|
||
|
||
TAGS="${ECR_IMAGE}"
|
||
|
||
if [ "${{ github.ref }}" = "refs/heads/main" ] && [ -n "$GHCR_IMAGE" ]; then
|
||
GHCR_AMD64="${GHCR_IMAGE}:latest-amd64"
|
||
GHCR_SHA="${GHCR_IMAGE}:${{ github.sha }}-amd64"
|
||
TAGS="${TAGS},$GHCR_AMD64,$GHCR_SHA"
|
||
|
||
if [ "${{ needs.detect-version.outputs.is_release }}" = "true" ]; then
|
||
VERSION="${{ needs.detect-version.outputs.version }}"
|
||
GHCR_VERSION="${GHCR_IMAGE}:${VERSION}-amd64"
|
||
TAGS="${TAGS},$GHCR_VERSION"
|
||
echo "📦 Adding version tag: ${VERSION}-amd64"
|
||
fi
|
||
fi
|
||
|
||
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Build and push images
|
||
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
|
||
with:
|
||
context: .
|
||
file: ${{ matrix.dockerfile }}
|
||
platforms: linux/amd64
|
||
push: true
|
||
tags: ${{ steps.meta.outputs.tags }}
|
||
provenance: false
|
||
sbom: false
|
||
|
||
# Build ARM64 images for GHCR (main branch only, runs in parallel)
|
||
build-ghcr-arm64:
|
||
name: Build ARM64 (GHCR Only)
|
||
needs: [detect-version]
|
||
runs-on: blacksmith-8vcpu-ubuntu-2404-arm
|
||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
- dockerfile: ./docker/app.Dockerfile
|
||
image: ghcr.io/simstudioai/simstudio
|
||
- dockerfile: ./docker/db.Dockerfile
|
||
image: ghcr.io/simstudioai/migrations
|
||
- dockerfile: ./docker/realtime.Dockerfile
|
||
image: ghcr.io/simstudioai/realtime
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||
|
||
- name: Login to GHCR
|
||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.repository_owner }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
|
||
|
||
- name: Generate ARM64 tags
|
||
id: meta
|
||
run: |
|
||
IMAGE="${{ matrix.image }}"
|
||
TAGS="${IMAGE}:latest-arm64,${IMAGE}:${{ github.sha }}-arm64"
|
||
|
||
# Add version tag if this is a release commit
|
||
if [ "${{ needs.detect-version.outputs.is_release }}" = "true" ]; then
|
||
VERSION="${{ needs.detect-version.outputs.version }}"
|
||
TAGS="${TAGS},${IMAGE}:${VERSION}-arm64"
|
||
echo "📦 Adding version tag: ${VERSION}-arm64"
|
||
fi
|
||
|
||
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Build and push ARM64 to GHCR
|
||
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
|
||
with:
|
||
context: .
|
||
file: ${{ matrix.dockerfile }}
|
||
platforms: linux/arm64
|
||
push: true
|
||
tags: ${{ steps.meta.outputs.tags }}
|
||
provenance: false
|
||
sbom: false
|
||
|
||
# Create GHCR multi-arch manifests (only for main, after both builds)
|
||
create-ghcr-manifests:
|
||
name: Create GHCR Manifests
|
||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||
needs: [build-amd64, build-ghcr-arm64, detect-version]
|
||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||
permissions:
|
||
packages: write
|
||
strategy:
|
||
matrix:
|
||
include:
|
||
- image: ghcr.io/simstudioai/simstudio
|
||
- image: ghcr.io/simstudioai/migrations
|
||
- image: ghcr.io/simstudioai/realtime
|
||
|
||
steps:
|
||
- name: Login to GHCR
|
||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.repository_owner }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Create and push manifests
|
||
run: |
|
||
IMAGE_BASE="${{ matrix.image }}"
|
||
|
||
# Create latest manifest
|
||
docker manifest create "${IMAGE_BASE}:latest" \
|
||
"${IMAGE_BASE}:latest-amd64" \
|
||
"${IMAGE_BASE}:latest-arm64"
|
||
docker manifest push "${IMAGE_BASE}:latest"
|
||
|
||
# Create SHA manifest
|
||
docker manifest create "${IMAGE_BASE}:${{ github.sha }}" \
|
||
"${IMAGE_BASE}:${{ github.sha }}-amd64" \
|
||
"${IMAGE_BASE}:${{ github.sha }}-arm64"
|
||
docker manifest push "${IMAGE_BASE}:${{ github.sha }}"
|
||
|
||
# Create version manifest if this is a release commit
|
||
if [ "${{ needs.detect-version.outputs.is_release }}" = "true" ]; then
|
||
VERSION="${{ needs.detect-version.outputs.version }}"
|
||
echo "📦 Creating version manifest: ${VERSION}"
|
||
docker manifest create "${IMAGE_BASE}:${VERSION}" \
|
||
"${IMAGE_BASE}:${VERSION}-amd64" \
|
||
"${IMAGE_BASE}:${VERSION}-arm64"
|
||
docker manifest push "${IMAGE_BASE}:${VERSION}"
|
||
fi
|
||
|
||
# Check if docs changed
|
||
check-docs-changes:
|
||
name: Check Docs Changes
|
||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||
outputs:
|
||
docs_changed: ${{ steps.filter.outputs.docs }}
|
||
steps:
|
||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||
with:
|
||
fetch-depth: 2 # Need at least 2 commits to detect changes
|
||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||
id: filter
|
||
with:
|
||
filters: |
|
||
docs:
|
||
- 'apps/docs/content/docs/en/**'
|
||
- 'apps/sim/scripts/process-docs.ts'
|
||
- 'apps/sim/lib/chunkers/**'
|
||
|
||
# Process docs embeddings (only when docs change, after ECR images are pushed)
|
||
process-docs:
|
||
name: Process Docs
|
||
needs: [build-amd64, check-docs-changes]
|
||
if: needs.check-docs-changes.outputs.docs_changed == 'true'
|
||
uses: ./.github/workflows/docs-embeddings.yml
|
||
secrets: inherit
|
||
|
||
# Create GitHub Release (only for version commits on main, after all builds complete)
|
||
create-release:
|
||
name: Create GitHub Release
|
||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||
needs: [create-ghcr-manifests, detect-version]
|
||
if: needs.detect-version.outputs.is_release == 'true'
|
||
permissions:
|
||
contents: write
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Setup Bun
|
||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||
with:
|
||
bun-version: 1.3.13
|
||
|
||
- name: Install dependencies
|
||
run: bun install --frozen-lockfile
|
||
|
||
- name: Create release
|
||
env:
|
||
GH_PAT: ${{ secrets.GITHUB_TOKEN }}
|
||
run: bun run scripts/create-single-release.ts ${{ needs.detect-version.outputs.version }}
|