Skip to content

feat(operator): investigate runs and findings in context #110

feat(operator): investigate runs and findings in context

feat(operator): investigate runs and findings in context #110

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
workflow_call:
inputs:
performance_baseline_revision:
description: Exact clean commit SHA used as the same-host release performance baseline
required: false
type: string
default: ''
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
NODE_VERSION: '22'
BUN_VERSION: '1.3.10'
jobs:
# ──────────────────────────────────────────────
# Lint — run ESLint across the workspace
# ──────────────────────────────────────────────
lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run ESLint
run: bun run lint
# ──────────────────────────────────────────────
# Typecheck — validate TypeScript across apps
# ──────────────────────────────────────────────
typecheck:
name: Typecheck
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Typecheck
run: |
bun run typecheck
bun --cwd=backend run typecheck:scripts
bun --cwd=backend run migration:typecheck
bun run typecheck:e2e
bun run typecheck:release-scripts
bun run smoke:findings-opensearch:typecheck
bun run smoke:telemetry-durability:typecheck
# ──────────────────────────────────────────────
# Unit Tests — bun test across the workspace
# ──────────────────────────────────────────────
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 25
services:
redis:
image: redis:7.4-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 12
env:
MCP_RUNTIME_TEST_REDIS_URL: redis://127.0.0.1:6379
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run release harness tests
run: bun test scripts/__tests__
- name: Run tests
run: bun run test
# ──────────────────────────────────────────────
# Tenant boundaries — named negative proof for the release gate
# ──────────────────────────────────────────────
tenant-boundaries:
name: Cross-Tenant Boundary Tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Backend ownership and redemption boundaries
run: >-
bun --cwd=backend test
src/api-keys/__tests__/api-keys.http.spec.ts
src/api-keys/__tests__/api-keys.service.spec.ts
src/integrations/__tests__/integrations.http.spec.ts
src/integrations/__tests__/integrations.repository.spec.ts
src/integrations/__tests__/integrations.service.spec.ts
src/mcp-servers/__tests__/mcp-servers.service.spec.ts
- name: Worker secret and file ownership boundaries
run: >-
bun --cwd=worker test
src/adapters/__tests__/secrets.adapter.test.ts
src/adapters/__tests__/file-storage.adapter.test.ts
# ──────────────────────────────────────────────
# Build — validate production build compiles
# ──────────────────────────────────────────────
build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [typecheck]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Build shared package
run: bun --cwd=packages/shared run build
- name: Build backend
run: bun --cwd=backend run build
- name: Build worker
run: bun --cwd=worker run build
- name: Build frontend
run: bun --cwd=frontend run build
# ──────────────────────────────────────────────
# API Contract — ensure OpenAPI spec is up to date
# ──────────────────────────────────────────────
api-contract:
name: API Contract Check
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Generate OpenAPI spec
run: bun --cwd=backend run generate:openapi
- name: Generate backend client
run: bun --cwd=packages/backend-client run generate
- name: Typecheck generated backend client
run: bun --cwd=packages/backend-client run typecheck
- name: Check for uncommitted API contract changes
run: |
if ! git diff --exit-code -- openapi.json packages/backend-client/src/client.ts; then
echo ""
echo "::error::OpenAPI or generated client is out of date. Regenerate both and commit the result."
exit 1
fi
# ──────────────────────────────────────────────
# Checked migrations — fresh, previous-release upgrade, and concurrent startup
# ──────────────────────────────────────────────
migration-smoke:
name: Checked Migration Smoke
runs-on: ubuntu-latest
timeout-minutes: 15
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: sentris_fresh
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d sentris_fresh"
--health-interval 5s
--health-timeout 5s
--health-retries 12
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Verify checked migration artifacts
run: bun --cwd=backend run migration:check
- name: Fresh database migration
env:
MIGRATION_SMOKE_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/sentris_fresh
run: bun --cwd=backend run migration:smoke:fresh
- name: Fresh database parity
env:
MIGRATION_SMOKE_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/sentris_fresh
run: bun --cwd=backend run migration:smoke:parity
- name: Create isolated upgrade database
run: >-
bun --cwd=backend -e "import pg from 'pg';
const client = new pg.Client('postgres://postgres:postgres@127.0.0.1:5432/postgres');
await client.connect();
await client.query('CREATE DATABASE sentris_upgrade');
await client.end();"
- name: Previous-release upgrade migration
env:
MIGRATION_SMOKE_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/sentris_upgrade
run: bun --cwd=backend run migration:smoke:upgrade
- name: Upgrade database parity
env:
MIGRATION_SMOKE_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/sentris_upgrade
run: bun --cwd=backend run migration:smoke:parity
- name: Create isolated concurrent-start database
run: >-
bun --cwd=backend -e "import pg from 'pg';
const client = new pg.Client('postgres://postgres:postgres@127.0.0.1:5432/postgres');
await client.connect();
await client.query('CREATE DATABASE sentris_concurrent');
await client.end();"
- name: Concurrent backend migration startup
env:
MIGRATION_SMOKE_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/sentris_concurrent
run: bun --cwd=backend run migration:smoke:concurrent
# ──────────────────────────────────────────────
# Production topology — real Temporal, DIND, telemetry, and target journey
# ──────────────────────────────────────────────
production-smoke:
name: Production Compose Release Smoke (${{ matrix.trust-profile }})
runs-on: ubuntu-latest
timeout-minutes: 180
needs: [lint, typecheck, test-unit, tenant-boundaries, build, api-contract, migration-smoke]
strategy:
fail-fast: false
matrix:
trust-profile: [trusted-local, hardened]
env:
CI: true
SENTRIS_INSTANCE: '0'
SENTRIS_TRUST_PROFILE: ${{ matrix.trust-profile }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Install Chromium for trusted-local browser journey
if: matrix.trust-profile == 'trusted-local'
run: bunx playwright install --with-deps chromium
- name: Run clean production topology and critical-journey smoke
run: bun run smoke:production-compose
# ──────────────────────────────────────────────
# Performance — same host, exact clean baseline/candidate revisions
# ──────────────────────────────────────────────
performance-pair:
name: Release Performance Pair
if: ${{ inputs.performance_baseline_revision != '' }}
runs-on: ubuntu-latest
timeout-minutes: 210
needs: [lint, typecheck, test-unit, tenant-boundaries, build, api-contract, migration-smoke]
env:
CI: 'true'
SENTRIS_INSTANCE: '0'
SENTRIS_TRUST_PROFILE: trusted-local
PERFORMANCE_BASELINE_REVISION: ${{ inputs.performance_baseline_revision }}
RELEASE_BENCHMARK_ADMIN_USERNAME: performance-admin
RELEASE_BENCHMARK_SAMPLE_COUNT: '10'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Cache Bun store
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-store-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-store-${{ runner.os }}-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Install Chromium
run: bunx playwright install --with-deps chromium
- name: Prepare isolated benchmark credentials
shell: bash
run: |
password="$(openssl rand -hex 32)"
token="$(openssl rand -hex 32)"
echo "::add-mask::$password"
echo "::add-mask::$token"
echo "RELEASE_BENCHMARK_ADMIN_PASSWORD=$password" >> "$GITHUB_ENV"
echo "RELEASE_BENCHMARK_INTERNAL_TOKEN=$token" >> "$GITHUB_ENV"
- name: Resolve exact candidate revision
id: candidate
shell: bash
run: echo "revision=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Prepare exact baseline worktree
shell: bash
run: |
if [[ ! "$PERFORMANCE_BASELINE_REVISION" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::Performance baseline must be a full 40-character commit SHA."
exit 1
fi
git worktree add --detach \
"$RUNNER_TEMP/sentris-baseline" \
"$PERFORMANCE_BASELINE_REVISION"
- name: Collect and compare release performance
shell: bash
env:
CANDIDATE_REVISION: ${{ steps.candidate.outputs.revision }}
run: |
bun run performance:pair -- \
--baseline-root "$RUNNER_TEMP/sentris-baseline" \
--baseline-revision "$PERFORMANCE_BASELINE_REVISION" \
--candidate-root "$GITHUB_WORKSPACE" \
--candidate-revision "$CANDIDATE_REVISION" \
--output-dir "$RUNNER_TEMP/sentris-performance-pair"
- name: Upload performance evidence
uses: actions/upload-artifact@v4
if: always()
with:
name: release-performance-pair
path: ${{ runner.temp }}/sentris-performance-pair/*.json
if-no-files-found: warn
retention-days: 30