наблюдаемость: завершить базовый контур Community
Добавить структурированные журналы, метрики, трассировку и безопасный канал критических ошибок. Усилить границы рантайма, тесты, проверку зависимостей и сценарии развёртывания.
This commit is contained in:
+118
-48
@@ -55,6 +55,9 @@ jobs:
|
||||
docker --version
|
||||
docker info
|
||||
|
||||
- name: Install dependency policy tool
|
||||
run: cargo install cargo-deny --version 0.20.2 --locked
|
||||
|
||||
- name: Run tooling unit tests
|
||||
run: python3 -m unittest discover -s tests/unit
|
||||
|
||||
@@ -67,6 +70,9 @@ jobs:
|
||||
- name: Check Rust code health
|
||||
run: scripts/check-rust-code-health.sh
|
||||
|
||||
- name: Check dependency licenses and advisories
|
||||
run: cargo deny --locked check advisories bans licenses sources
|
||||
|
||||
- name: Check Rust boundaries
|
||||
run: scripts/check-rust-boundaries.sh
|
||||
|
||||
@@ -95,6 +101,10 @@ jobs:
|
||||
working-directory: apps/ui
|
||||
run: npm ci
|
||||
|
||||
- name: Audit UI dependencies
|
||||
working-directory: apps/ui
|
||||
run: npm audit --audit-level=high
|
||||
|
||||
- name: Build UI bundle
|
||||
working-directory: apps/ui
|
||||
run: npm run build
|
||||
@@ -179,9 +189,11 @@ jobs:
|
||||
find .tmp/ui-e2e/logs -maxdepth 1 -type f -print -exec sed -n '1,220p' {} \; || true
|
||||
|
||||
deployment:
|
||||
name: Deployment Manifests
|
||||
name: Community Image Smoke
|
||||
runs-on: ubuntu-latest
|
||||
needs: ui
|
||||
needs:
|
||||
- rust
|
||||
- ui
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -190,6 +202,58 @@ jobs:
|
||||
- name: Validate Community deployment manifest
|
||||
run: docker compose -f deploy/community/docker-compose.yml --env-file deploy/community/.env.example config -q
|
||||
|
||||
- name: Build Community images
|
||||
run: |
|
||||
docker build -f apps/admin-api/Dockerfile -t crank/admin-api:ci .
|
||||
docker build -f apps/mcp-server/Dockerfile -t crank/mcp-server:ci .
|
||||
docker build -f apps/ui/Dockerfile -t crank/ui:ci .
|
||||
|
||||
- name: Start Community image stack
|
||||
run: |
|
||||
mkdir -p .tmp
|
||||
cat > .tmp/community-smoke.env <<'EOF'
|
||||
COMPOSE_PROJECT_NAME=crank-ci-smoke
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=crank
|
||||
POSTGRES_USER=crank
|
||||
POSTGRES_PASSWORD=crank-ci-password
|
||||
CRANK_ADMIN_API_IMAGE=crank/admin-api:ci
|
||||
CRANK_MCP_SERVER_IMAGE=crank/mcp-server:ci
|
||||
CRANK_UI_IMAGE=crank/ui:ci
|
||||
CRANK_MASTER_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
CRANK_SESSION_SECRET=ci-session-secret
|
||||
CRANK_PASSWORD_PEPPER=ci-password-pepper
|
||||
CRANK_BOOTSTRAP_ADMIN_EMAIL=owner@crank.test
|
||||
CRANK_BOOTSTRAP_ADMIN_PASSWORD=ci-admin-password
|
||||
CRANK_BOOTSTRAP_ADMIN_DISPLAY_NAME=CI Owner
|
||||
CRANK_BASE_URL=http://127.0.0.1:3000
|
||||
CRANK_PUBLISH_BIND=127.0.0.1
|
||||
CRANK_DEMO_SEED=true
|
||||
EOF
|
||||
docker compose -f deploy/community/docker-compose.images.yml \
|
||||
--env-file .tmp/community-smoke.env --profile local-db up -d --wait
|
||||
|
||||
- name: Run authenticated Community image smoke
|
||||
env:
|
||||
CRANK_STAGING_ADMIN_EMAIL: owner@crank.test
|
||||
CRANK_STAGING_ADMIN_PASSWORD: ci-admin-password
|
||||
run: scripts/authenticated-product-smoke.sh http://127.0.0.1:3000
|
||||
|
||||
- name: Show Community image logs
|
||||
if: failure()
|
||||
run: |
|
||||
docker compose -f deploy/community/docker-compose.images.yml \
|
||||
--env-file .tmp/community-smoke.env --profile local-db ps || true
|
||||
docker compose -f deploy/community/docker-compose.images.yml \
|
||||
--env-file .tmp/community-smoke.env --profile local-db logs --no-color || true
|
||||
|
||||
- name: Stop Community image stack
|
||||
if: always()
|
||||
run: |
|
||||
docker compose -f deploy/community/docker-compose.images.yml \
|
||||
--env-file .tmp/community-smoke.env --profile local-db down -v --remove-orphans || true
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
runs-on: ubuntu-latest
|
||||
@@ -245,6 +309,10 @@ jobs:
|
||||
-t '${{ env.UI_IMAGE }}:${{ env.IMAGE_TAG }}' \
|
||||
-t '${{ env.UI_IMAGE }}:main' \
|
||||
.
|
||||
scripts/scan-images.sh \
|
||||
'${{ env.ADMIN_API_IMAGE }}:${{ env.IMAGE_TAG }}' \
|
||||
'${{ env.MCP_SERVER_IMAGE }}:${{ env.IMAGE_TAG }}' \
|
||||
'${{ env.UI_IMAGE }}:${{ env.IMAGE_TAG }}'
|
||||
docker push '${{ env.ADMIN_API_IMAGE }}:${{ env.IMAGE_TAG }}'
|
||||
docker push '${{ env.ADMIN_API_IMAGE }}:main'
|
||||
docker push '${{ env.MCP_SERVER_IMAGE }}:${{ env.IMAGE_TAG }}'
|
||||
@@ -274,9 +342,14 @@ jobs:
|
||||
run: |
|
||||
. "$OPENBAO_ENV_FILE"
|
||||
ssh -p "$DEPLOY_PORT" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||||
"mkdir -p '$DEPLOY_PATH'"
|
||||
"mkdir -p '$DEPLOY_PATH' && \
|
||||
if [ -f '$DEPLOY_PATH/docker-compose.yml' ]; then \
|
||||
cp '$DEPLOY_PATH/docker-compose.yml' '$DEPLOY_PATH/docker-compose.previous.yml'; \
|
||||
fi"
|
||||
rsync -az -e "ssh -p $DEPLOY_PORT" deploy/community/docker-compose.yml \
|
||||
"$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/docker-compose.yml"
|
||||
rsync -az -e "ssh -p $DEPLOY_PORT" scripts/deploy-community.sh \
|
||||
"$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/deploy-community.sh"
|
||||
|
||||
- name: Write environment file
|
||||
run: |
|
||||
@@ -292,6 +365,11 @@ jobs:
|
||||
append_if_set POSTGRES_USER "$POSTGRES_USER"
|
||||
append_if_set POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
|
||||
append_if_set POSTGRES_HOST "$POSTGRES_HOST"
|
||||
append_if_set POSTGRES_MAX_CONNECTIONS "${POSTGRES_MAX_CONNECTIONS:-}"
|
||||
append_if_set POSTGRES_MIN_CONNECTIONS "${POSTGRES_MIN_CONNECTIONS:-}"
|
||||
append_if_set POSTGRES_ACQUIRE_TIMEOUT_MS "${POSTGRES_ACQUIRE_TIMEOUT_MS:-}"
|
||||
append_if_set POSTGRES_IDLE_TIMEOUT_MS "${POSTGRES_IDLE_TIMEOUT_MS:-}"
|
||||
append_if_set POSTGRES_MAX_LIFETIME_MS "${POSTGRES_MAX_LIFETIME_MS:-}"
|
||||
if [ -n "${POSTGRES_PORT:-}" ]; then
|
||||
append_if_set POSTGRES_PORT "$POSTGRES_PORT"
|
||||
elif [ -n "${PGBOUNCER_PORT:-}" ]; then
|
||||
@@ -302,10 +380,35 @@ jobs:
|
||||
append_if_set CRANK_ADMIN_BIND "$CRANK_ADMIN_BIND"
|
||||
append_if_set CRANK_MCP_BIND "$CRANK_MCP_BIND"
|
||||
append_if_set CRANK_MCP_REFRESH_MS "$CRANK_MCP_REFRESH_MS"
|
||||
append_if_set CRANK_ADMIN_RATE_LIMIT_RPS "${CRANK_ADMIN_RATE_LIMIT_RPS:-}"
|
||||
append_if_set CRANK_ADMIN_RATE_LIMIT_BURST "${CRANK_ADMIN_RATE_LIMIT_BURST:-}"
|
||||
append_if_set CRANK_MCP_RATE_LIMIT_RPS "${CRANK_MCP_RATE_LIMIT_RPS:-}"
|
||||
append_if_set CRANK_MCP_RATE_LIMIT_BURST "${CRANK_MCP_RATE_LIMIT_BURST:-}"
|
||||
append_if_set CRANK_RUNTIME_MAX_CONCURRENT_UNARY "${CRANK_RUNTIME_MAX_CONCURRENT_UNARY:-}"
|
||||
append_if_set CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS "${CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS:-}"
|
||||
append_if_set CRANK_OUTBOUND_ALLOWED_HOSTS "${CRANK_OUTBOUND_ALLOWED_HOSTS:-}"
|
||||
append_if_set CRANK_OUTBOUND_DENIED_HOSTS "${CRANK_OUTBOUND_DENIED_HOSTS:-}"
|
||||
append_if_set CRANK_OUTBOUND_MAX_RESPONSE_BYTES "${CRANK_OUTBOUND_MAX_RESPONSE_BYTES:-}"
|
||||
append_if_set CRANK_ENVIRONMENT "${CRANK_ENVIRONMENT:-production}"
|
||||
append_if_set CRANK_LOG_LEVEL "$CRANK_LOG_LEVEL"
|
||||
append_if_set CRANK_SENTRY_DSN "${CRANK_SENTRY_DSN:-}"
|
||||
append_if_set CRANK_METRICS_ENABLED "${CRANK_METRICS_ENABLED:-}"
|
||||
append_if_set CRANK_ADMIN_METRICS_BIND "${CRANK_ADMIN_METRICS_BIND:-}"
|
||||
append_if_set CRANK_MCP_METRICS_BIND "${CRANK_MCP_METRICS_BIND:-}"
|
||||
append_if_set CRANK_METRICS_BEARER_TOKEN "${CRANK_METRICS_BEARER_TOKEN:-}"
|
||||
append_if_set CRANK_INVOCATION_LOG_RETENTION_DAYS "${CRANK_INVOCATION_LOG_RETENTION_DAYS:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_ENDPOINT "${OTEL_EXPORTER_OTLP_ENDPOINT:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_TRACES_ENDPOINT "${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_PROTOCOL "${OTEL_EXPORTER_OTLP_PROTOCOL:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_TRACES_PROTOCOL "${OTEL_EXPORTER_OTLP_TRACES_PROTOCOL:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_TIMEOUT "${OTEL_EXPORTER_OTLP_TIMEOUT:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_TRACES_TIMEOUT "${OTEL_EXPORTER_OTLP_TRACES_TIMEOUT:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_HEADERS "${OTEL_EXPORTER_OTLP_HEADERS:-}"
|
||||
append_if_set OTEL_EXPORTER_OTLP_TRACES_HEADERS "${OTEL_EXPORTER_OTLP_TRACES_HEADERS:-}"
|
||||
append_if_set OTEL_BSP_MAX_QUEUE_SIZE "${OTEL_BSP_MAX_QUEUE_SIZE:-}"
|
||||
append_if_set OTEL_BSP_MAX_EXPORT_BATCH_SIZE "${OTEL_BSP_MAX_EXPORT_BATCH_SIZE:-}"
|
||||
append_if_set OTEL_BSP_SCHEDULE_DELAY "${OTEL_BSP_SCHEDULE_DELAY:-}"
|
||||
append_if_set OTEL_BSP_EXPORT_TIMEOUT "${OTEL_BSP_EXPORT_TIMEOUT:-}"
|
||||
append_if_set CRANK_MASTER_KEY "$CRANK_MASTER_KEY"
|
||||
append_if_set CRANK_BASE_URL "$CRANK_BASE_URL"
|
||||
append_if_set CRANK_CACHE_BACKEND "$CRANK_CACHE_BACKEND"
|
||||
@@ -325,7 +428,10 @@ jobs:
|
||||
printf 'CRANK_UI_IMAGE=%s:%s\n' '${{ env.UI_IMAGE }}' '${{ env.IMAGE_TAG }}'
|
||||
} >> "$tmp_env"
|
||||
cat "$tmp_env" | ssh -p "$DEPLOY_PORT" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||||
"mkdir -p '$DEPLOY_PATH' && cat > '$DEPLOY_PATH/.env'"
|
||||
"mkdir -p '$DEPLOY_PATH' && \
|
||||
if [ -f '$DEPLOY_PATH/.env' ]; then \
|
||||
cp '$DEPLOY_PATH/.env' '$DEPLOY_PATH/.env.previous'; \
|
||||
fi && cat > '$DEPLOY_PATH/.env'"
|
||||
rm -f "$tmp_env"
|
||||
|
||||
- name: Validate required environment variables
|
||||
@@ -359,48 +465,12 @@ jobs:
|
||||
- name: Deploy with Docker Compose
|
||||
run: |
|
||||
. "$OPENBAO_ENV_FILE"
|
||||
ssh -p "$DEPLOY_PORT" "$DEPLOY_USER@$DEPLOY_HOST" "
|
||||
set -e
|
||||
cd '$DEPLOY_PATH'
|
||||
compose_profiles=''
|
||||
cache_backend=\$(grep -E '^CRANK_CACHE_BACKEND=' .env | tail -n1 | cut -d= -f2- || true)
|
||||
if [ \"\$cache_backend\" = 'valkey' ] || [ \"\$cache_backend\" = 'redis' ]; then
|
||||
compose_profiles='--profile cache'
|
||||
fi
|
||||
echo '$DEPLOY_REGISTRY_TOKEN' | docker login '${{ env.REGISTRY }}' -u '$DEPLOY_REGISTRY_USER' --password-stdin
|
||||
docker compose \$compose_profiles config -q
|
||||
docker compose \$compose_profiles pull
|
||||
docker compose \$compose_profiles down --remove-orphans
|
||||
for container in \
|
||||
crank-ui-1 \
|
||||
crank-admin-api-1 \
|
||||
crank-mcp-server-1 \
|
||||
crank-postgres-1 \
|
||||
crank-valkey-1 \
|
||||
crank-community-ui-1 \
|
||||
crank-community-admin-api-1 \
|
||||
crank-community-mcp-server-1 \
|
||||
crank-community-postgres-1 \
|
||||
crank-community-valkey-1; do
|
||||
if docker ps -a --format '{{.Names}}' | grep -Fx \"\$container\" >/dev/null; then
|
||||
docker rm -f \"\$container\"
|
||||
fi
|
||||
done
|
||||
echo 'Docker containers before freeing required ports:'
|
||||
docker ps --format 'table {{.ID}}\t{{.Names}}\t{{.Ports}}'
|
||||
for port in 3000 3001 3002; do
|
||||
container_ids=\$(docker ps -aq --filter \"publish=\$port\")
|
||||
if [ -n \"\$container_ids\" ]; then
|
||||
echo \"Removing containers publishing port \$port\"
|
||||
docker inspect --format '{{.Name}} {{json .NetworkSettings.Ports}}' \$container_ids || true
|
||||
docker rm -f \$container_ids
|
||||
fi
|
||||
done
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -ltnp '( sport = :3000 or sport = :3001 or sport = :3002 )' || true
|
||||
fi
|
||||
docker compose \$compose_profiles up -d --remove-orphans
|
||||
"
|
||||
printf '%s' "$DEPLOY_REGISTRY_TOKEN" | ssh -p "$DEPLOY_PORT" \
|
||||
"$DEPLOY_USER@$DEPLOY_HOST" \
|
||||
"docker login '${{ env.REGISTRY }}' -u '$DEPLOY_REGISTRY_USER' --password-stdin"
|
||||
ssh -p "$DEPLOY_PORT" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||||
"chmod 700 '$DEPLOY_PATH/deploy-community.sh' && \
|
||||
'$DEPLOY_PATH/deploy-community.sh' '$DEPLOY_PATH'"
|
||||
|
||||
- name: Verify health endpoints
|
||||
run: |
|
||||
@@ -410,8 +480,8 @@ jobs:
|
||||
cd '$DEPLOY_PATH'
|
||||
for attempt in \$(seq 1 30); do
|
||||
if curl --fail --silent http://127.0.0.1:3000/ >/dev/null \
|
||||
&& curl --fail --silent http://127.0.0.1:3001/health >/dev/null \
|
||||
&& curl --fail --silent http://127.0.0.1:3002/health >/dev/null; then
|
||||
&& curl --fail --silent http://127.0.0.1:3001/ready >/dev/null \
|
||||
&& curl --fail --silent http://127.0.0.1:3002/ready >/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
|
||||
Reference in New Issue
Block a user