Files
knowledge-governance/compose.yaml
T
姚章浩 533db535f1
build / build (push) Successful in 1m12s
feat(qaops): 接入真实模型补缺任务与总表看板
按已确认需求提供独立安全模型配置、真实探测、正式字典字段评估与原问题译中,持久批次支持只补空白、暂停恢复、有限重试、幂等和逐字段依据。覆盖固定规则、本地语言、组织关联与主表有效看板共用治理侧读模型,保留源生产和冻结历史。

验证:完整 make verify 退出0,702项Go与329项前端通过;默认118项外部/隔离集成明确跳过,另跑完整镜像及组织隔离PG竞态。12并发、输入漂移、过期租约、暂停/恢复及有限重试通过。用户授权的百炼 deepseek-v4.1-flash 完成真实后台与浏览器评估/翻译;552行、16列、11块看板及完整PNG、独立配置页测试/保存、重开恢复和零JS异常通过。仅非业务样本外发,自动处理关闭,原payload不变。

上线前治理库已做导出快照原生备份并真实恢复,60表行数与17个QA表内容哈希一致;不修改DobotAI生产或隧道。本提交时尚未部署,线上验收须独立完成。
2026-10-19 14:29:49 +08:00

248 lines
10 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: knowledge-governance-p1
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: governance
POSTGRES_USER: governance
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
secrets:
- postgres_password
volumes:
- governance-pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U governance -d governance"]
interval: 5s
timeout: 3s
retries: 20
restart: unless-stopped
api:
build:
context: .
dockerfile: Dockerfile
command: ["/app/api"]
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
<<: &app-environment
DATABASE_URL: postgres://governance@postgres:5432/governance?sslmode=disable
PGPASSFILE: /run/secrets/pgpass
APP_ADDR: :8080
WORKER_POLL_INTERVAL: 1s
WORKER_LEASE_DURATION: 30s
WORKER_RETRY_DELAY: 5s
TEST_WEKNORA_BASE_URL: "${TEST_WEKNORA_BASE_URL:-}"
# 验收通过后是否自动批准:off | internal(默认,仅对内;对外仍需人工)| all。
# 只影响"审核"这一步;生产发布的双闸、人工授权与发布前快照门禁不受影响。
TEST_AUTO_REVIEW_POLICY: "${TEST_AUTO_REVIEW_POLICY:-internal}"
DINGTALK_LOGIN_SIDECAR_URL: "http://dingtalk-login:8091"
MINERU_BASE_URL: "${MINERU_BASE_URL:-}"
TEST_INTERNAL_WEKNORA_KB_ID: "${TEST_INTERNAL_WEKNORA_KB_ID:-1b52c140-2e18-4676-afc5-4c7d8d190a8c}"
TEST_EXTERNAL_WEKNORA_KB_ID: "${TEST_EXTERNAL_WEKNORA_KB_ID:-fd7db6aa-763a-46f1-84d2-ecc7c952a5ea}"
# 「版本记录」页:**匿名只读**远端仓库的提交与 tag(不使用任何凭据)。
# 留空 = 未接线(页面降级、同步入口不可用);来源只允许下面批准的 origin 与固定仓库。
VERSION_HISTORY_GITEA_BASE_URL: "${VERSION_HISTORY_GITEA_BASE_URL:-}"
VERSION_HISTORY_REPO: "${VERSION_HISTORY_REPO:-Weknora/knowledge-governance}"
VERSION_HISTORY_ALLOWED_ORIGINS: "${VERSION_HISTORY_ALLOWED_ORIGINS:-}"
# 页面链接用的 origin(给内网外的浏览器点开);留空 = 与抓取 origin 相同。
VERSION_HISTORY_LINK_ORIGIN: "${VERSION_HISTORY_LINK_ORIGIN:-}"
VERSION_HISTORY_HTTP_TIMEOUT: "${VERSION_HISTORY_HTTP_TIMEOUT:-15s}"
VERSION_HISTORY_MAX_PAGES: "${VERSION_HISTORY_MAX_PAGES:-200}"
# Mount this independent master-key file read-only using the deployment overlay.
QA_AI_MASTER_KEY_FILE: "${QA_AI_MASTER_KEY_FILE:-}"
QA_AI_DNS_OVER_TLS: "${QA_AI_DNS_OVER_TLS:-}"
QA_AI_TRUST_TLS_PROXY: "${QA_AI_TRUST_TLS_PROXY:-false}"
# P10 readiness probe reads the routing KB with the same scoped key.
TEST_WEKNORA_API_KEY_FILE: /run/secrets/test_weknora_api_key
TEST_WEKNORA_ALLOW_DOCKER_HTTP: "${TEST_WEKNORA_ALLOW_DOCKER_HTTP:-false}"
WORKER_LIVENESS_STALE_AFTER: "${WORKER_LIVENESS_STALE_AFTER:-2m}"
PRODUCTION_RELEASE_REQUESTS_ENABLED: ${PRODUCTION_RELEASE_REQUESTS_ENABLED:-false}
PRODUCTION_BACKUP_RESTORE_VERIFIED: ${PRODUCTION_BACKUP_RESTORE_VERIFIED:-false}
# Read-only probe of the production WeKnora endpoint; publishing keeps
# reading its target from RELEASE_CONFIG_FILE.
PRODUCTION_WEKNORA_BASE_URL: "${PRODUCTION_WEKNORA_BASE_URL:-}"
PRODUCTION_WEKNORA_API_KEY_FILE: "${PRODUCTION_WEKNORA_API_KEY_FILE:-}"
PRODUCTION_WEKNORA_ALLOW_DOCKER_HTTP: "${PRODUCTION_WEKNORA_ALLOW_DOCKER_HTTP:-false}"
# 数据源发现(系统设置 → 数据源配置):api 用 dws 只读列举钉钉知识库与钉盘空间。
DWS_BIN: /usr/local/bin/dws
DWS_CONFIG_DIR: /data/dws
DWS_HOME: /data/home
DWS_DISABLE_KEYCHAIN: "1"
secrets:
- pgpass
- test_weknora_api_key
volumes:
# 与 worker 共用同一份 dws 状态:refresh token 是轮换制,绝不能在两处各留一份。
- /home/zheromiku/.dws:/data/dws
# dws 的文件型 keychain 必须有 $HOME/.local/share/dws-cli,故挂到 DWS_HOME 下。
- /home/zheromiku/.local/share/dws-cli:/data/home/.local/share/dws-cli
depends_on:
postgres:
condition: service_healthy
healthcheck:
# P10: liveness only — a third-party outage must never restart the API.
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/livez"]
interval: 5s
timeout: 3s
retries: 20
read_only: true
tmpfs:
- /tmp
networks:
- default
- weknora-local
restart: unless-stopped
worker:
build:
context: .
dockerfile: Dockerfile
command: ["/app/worker"]
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
<<: *app-environment
WORKER_ID: worker-1
QA_AI_MASTER_KEY_FILE: "${QA_AI_MASTER_KEY_FILE:-}"
QA_AI_DNS_OVER_TLS: "${QA_AI_DNS_OVER_TLS:-}"
PP_SCAN_ENABLED: "${PP_SCAN_ENABLED:-false}"
PP_SCAN_ALLOWED_ROOT: "${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}"
PP_SCAN_LEDGER_PATH: "${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}/public-weknora-sync/state.jsonl"
PP_SCAN_MANIFEST_PATH: "${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}/public-documents/manifest.json"
TEST_WEKNORA_ENABLED: "${TEST_WEKNORA_ENABLED:-false}"
TEST_WEKNORA_ALLOW_DOCKER_HTTP: "${TEST_WEKNORA_ALLOW_DOCKER_HTTP:-false}"
TEST_WEKNORA_KB_ID: "${TEST_WEKNORA_KB_ID:-}"
TEST_WEKNORA_API_KEY_FILE: /run/secrets/test_weknora_api_key
GOVERNANCE_SPOOL_ROOT: /var/lib/governance/spool
INGESTION_SPOOL_ROOT: /var/lib/governance/ingestion
TEST_WEKNORA_HTTP_TIMEOUT: "${TEST_WEKNORA_HTTP_TIMEOUT:-60s}"
TEST_WEKNORA_POLL_INITIAL: "${TEST_WEKNORA_POLL_INITIAL:-10s}"
TEST_WEKNORA_POLL_MAX: "${TEST_WEKNORA_POLL_MAX:-60s}"
TEST_WEKNORA_STALLED_AFTER: "${TEST_WEKNORA_STALLED_AFTER:-30m}"
TEST_WEKNORA_MAX_UPLOAD_BYTES: "${TEST_WEKNORA_MAX_UPLOAD_BYTES:-52428800}"
TEST_ACCEPTANCE_POLICY_VERSION: "${TEST_ACCEPTANCE_POLICY_VERSION:-structural-v1}"
# DingTalk 取件走 dws(默认优先 dws,可重试失败回落老路径):dws|auto|legacy
ARTIFACT_DINGTALK_FETCHER: "${ARTIFACT_DINGTALK_FETCHER:-auto}"
DWS_BIN: /usr/local/bin/dws
DWS_CONFIG_DIR: /data/dws
# dws 的文件型 keychain 在 $HOME/.local/share/dws-cli(XDG_DATA_HOME 不被识别),
# 仅给 dws 子进程换 HOME,不动整个 worker 的 HOME。
DWS_HOME: /data/home
DWS_DISABLE_KEYCHAIN: "1"
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
secrets:
- pgpass
- test_weknora_api_key
volumes:
- ./spool:/var/lib/governance/spool:ro
- ./spool/ingestion:/var/lib/governance/ingestion
- "${PP_SCAN_HOST_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}:${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}:ro"
- /home/zheromiku/dingtalk_kb_download:/sources/dingtalk:ro
# dws 凭据:与宿主共享同一份 state(refresh token 是轮换制,不能在两处各留一份)
- /home/zheromiku/.dws:/data/dws
# dws 的文件型 keychain:必须有 $HOME/.local/share/dws-cli,故挂到 DWS_HOME 下
- /home/zheromiku/.local/share/dws-cli:/data/home/.local/share/dws-cli
- /home/zheromiku/tmp/alist:/sources/alist:ro
- /home/zheromiku/dobot-portal-sync:/sources/pp:ro
- ./secrets/dingtalk_capture.json:/run/source-secrets/dingtalk_capture.json:ro
- ./secrets/alist_connections.xlsx:/run/source-secrets/alist_connections.xlsx:ro
- ./secrets/alist_api_token:/run/source-secrets/alist_api_token:ro
- ./secrets/pp_credentials.json:/run/source-secrets/pp_credentials.json:ro
networks:
- default
- weknora-local
depends_on:
postgres:
condition: service_healthy
read_only: true
tmpfs:
- /tmp
restart: unless-stopped
release-worker:
build:
context: .
dockerfile: Dockerfile
command: ["/app/release-worker"]
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
<<: *app-environment
WORKER_ID: release-worker-1
RELEASE_WORKER_ENABLED: "false"
RELEASE_CONFIG_FILE: ""
secrets:
- pgpass
depends_on:
postgres:
condition: service_healthy
read_only: true
tmpfs:
- /tmp
restart: unless-stopped
dingtalk-login:
# Chromium profile for DingTalk scan sessions. The bind-mounted secrets
# directory is rw ONLY here; the worker keeps reading the capture read-only.
build:
context: ./services/dingtalk-login
image: knowledge-governance-dingtalk-login:local
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
CAPTURE_FILE: /run/source-secrets/dingtalk_capture.json
DINGTALK_STATE_FILE: /sources/dingtalk/data/dingtalk-internal/inventory-state.json
VERIFY_SPACE: "${DINGTALK_VERIFY_SPACE:-9JOGO6332vlBnm4Q}"
QR_TTL_MS: "300000"
volumes:
- ./secrets:/run/source-secrets
- /home/zheromiku/dingtalk_kb_download:/sources/dingtalk
- dingtalk-chromium-profile:/profile
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:8091/healthz',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"]
interval: 10s
timeout: 5s
retries: 30
start_period: 15s
restart: unless-stopped
web:
build:
context: .
dockerfile: Dockerfile.web
ports:
- "8088:8080"
depends_on:
api:
condition: service_healthy
read_only: true
volumes:
# 上一版构建的静态资源(只读,由部署脚本落盘):CDN/浏览器可能还持有旧 index.html,
# 让它的旧哈希引用不至于 404 —— 否则页面会空白或"只有文字没样式"。
- ./deploy/legacy-assets:/usr/share/nginx/legacy:ro
tmpfs:
- /tmp
- /var/cache/nginx
- /var/run
restart: unless-stopped
secrets:
postgres_password:
file: ./secrets/postgres_password
pgpass:
file: ./secrets/pgpass
test_weknora_api_key:
file: ./secrets/test_weknora_api_key
volumes:
governance-pgdata:
dingtalk-chromium-profile:
networks:
weknora-local:
external: true
name: weknora071full-network