Files
ai-contract-platform/yuqei-infra/deploy/README.md
T
yuqei ce7e040e98
Build and Test Quality Gate / Contract Web typecheck and build (pull_request) Successful in 7m28s
Build and Test Quality Gate / Python tests and Contract API migration (pull_request) Failing after 26m12s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Successful in 6m33s
feat: close production trust and operations gates
2026-08-12 12:58:10 +08:00

5.8 KiB

V2 production backend deployment

The production backend runs on 192.168.3.90; Contract Web is deployed separately to Alibaba Cloud. The production compose override therefore disables Contract Web by default and exposes only the HTTPS edge service publicly.

Files

  • ../compose/docker-compose.yml: shared service definitions used by local and smoke environments.
  • ../compose/docker-compose.production.yml: backend-only production image, volume, TLS edge, and backup-helper overrides.
  • ../compose/docker-compose.production.smtp.yml: optional SMTP password secret mount; include only when email delivery mode is smtp.
  • ../compose/.env.production.example: reviewed variable inventory. The real file belongs at /etc/yuqei/production.env, mode 0600, outside the repository.
  • preflight-production.py: read-only production configuration gate.

Prepare without changing traffic

  1. Create an immutable RC commit and publish the three application images by digest. Pin PostgreSQL/pgvector, Redis, MinIO, mc, Nginx, and the backup helper by digest as well.
  2. Create a new production PostgreSQL/volume set. Do not reuse or rename the smoke database or volumes.
  3. Mount an off-host backup filesystem at BACKUP_HOST_DIR.
  4. Place tls.crt, tls.key, and the AI provider key in protected host directories. When enabling SMTP, also create the file named by CONTRACT_API_IDENTITY_SMTP_PASSWORD_FILE_HOST, mode 0600.
  5. Copy .env.production.example to /etc/yuqei/production.env, replace every placeholder, and keep mode 0600. Create the file named by PRODUCTION_ALERT_WEBHOOK_URL_FILE, containing only the approved HTTPS alert receiver URL. Keep it owner-only and readable by the nobody account used by the production health unit (for example, owner nobody:nobody, mode 0600).
  6. Run the read-only gate:
python3 yuqei-infra/deploy/preflight-production.py \
  --env-file /etc/yuqei/production.env \
  --artifact-dir /var/lib/yuqei/preflight
  1. Validate and pull images without starting services:
docker compose \
  --project-name yuqei-v2-production \
  --env-file /etc/yuqei/production.env \
  -f yuqei-infra/compose/docker-compose.yml \
  -f yuqei-infra/compose/docker-compose.production.yml \
  config --quiet

docker compose \
  --project-name yuqei-v2-production \
  --env-file /etc/yuqei/production.env \
  -f yuqei-infra/compose/docker-compose.yml \
  -f yuqei-infra/compose/docker-compose.production.yml \
  pull

These commands do not start containers and do not switch traffic.

Optional SMTP secret

The default production example keeps identity email delivery disabled; it does not require an SMTP password file or the SMTP compose overlay. To enable SMTP, set the SMTP mode and related transport fields in the protected production env file, set manual invitations to false, then append the opt-in override to every production Compose command:

docker compose \
  --project-name yuqei-v2-production \
  --env-file /etc/yuqei/production.env \
  -f yuqei-infra/compose/docker-compose.yml \
  -f yuqei-infra/compose/docker-compose.production.yml \
  -f yuqei-infra/compose/docker-compose.production.smtp.yml \
  config --quiet

The override mounts CONTRACT_API_IDENTITY_SMTP_PASSWORD_FILE_HOST as /run/secrets/contract_smtp_password and clears the direct password environment variable. Do not include this override in disabled-mode deployments. The preflight gate checks that an authenticated SMTP configuration uses an absolute, non-empty, owner-only host secret file and an encrypted transport mode.

Provider secret and model config

The provider key file is mounted at /run/secrets/ai_provider_api_key. The enabled default model config must use:

api_key_secret_ref=file:///run/secrets/ai_provider_api_key

Do not send the key in the model-config API payload. Run the Provider acceptance gate before any production start approval.

The production Provider canary is read-only. Run the protected provider-promotion-canary.yml workflow against at least two distinct HTTPS nodes after the signed receipt, public keyring, immutable release and image digest are pinned. The gate sends Cache-Control: no-cache, no-store and fails closed unless every response:

  • declares environment=production and verification_mode=offline_read_only;
  • is fresh within max_observation_age_seconds (120 seconds by default);
  • reports consistent top-level, check-detail, and promotion-diagnostic state; and
  • matches the expected release, receipt, signing key and image digest.

Revocation and kill-switch modes apply the same provenance and freshness checks after all nodes report the blocking control. The workflow performs GET requests only; it does not change a keyring, toggle the kill switch, import a receipt, or invoke any identity write/execute API. Make control changes through the independently approved operations procedure, then use this workflow only to observe their propagation.

Alibaba Cloud frontend variables

The frontend deployment must use server-only values:

CONTRACT_API_BASE_URL=https://<backend-domain>/contract
AI_PLATFORM_API_BASE_URL=https://<backend-domain>/ai
CONTRACT_API_PROXY_SECRET=<same protected proxy secret as Contract API>
AI_PLATFORM_PROXY_SECRET=<same protected AI service secret as AI Platform>
CONTRACT_WEB_SESSION_SECRET=<independent protected session secret>
CONTRACT_WEB_SESSION_SECURE=true

Do not expose any of these secrets through NEXT_PUBLIC_* variables. The browser should call only same-origin Contract Web API routes.

Traffic boundary

Starting postgres, redis, minio, migrations, APIs, and workers is a backend deployment. Starting edge or changing Alibaba Cloud frontend variables/DNS is a separate traffic-change approval. This repository intentionally does not provide an automatic production cutover command.