533db535f1
build / build (push) Successful in 1m12s
按已确认需求提供独立安全模型配置、真实探测、正式字典字段评估与原问题译中,持久批次支持只补空白、暂停恢复、有限重试、幂等和逐字段依据。覆盖固定规则、本地语言、组织关联与主表有效看板共用治理侧读模型,保留源生产和冻结历史。 验证:完整 make verify 退出0,702项Go与329项前端通过;默认118项外部/隔离集成明确跳过,另跑完整镜像及组织隔离PG竞态。12并发、输入漂移、过期租约、暂停/恢复及有限重试通过。用户授权的百炼 deepseek-v4.1-flash 完成真实后台与浏览器评估/翻译;552行、16列、11块看板及完整PNG、独立配置页测试/保存、重开恢复和零JS异常通过。仅非业务样本外发,自动处理关闭,原payload不变。 上线前治理库已做导出快照原生备份并真实恢复,60表行数与17个QA表内容哈希一致;不修改DobotAI生产或隧道。本提交时尚未部署,线上验收须独立完成。
248 lines
10 KiB
YAML
248 lines
10 KiB
YAML
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
|