From 0c69484c55da11c55bdb3f5b8eac356afc3932ff Mon Sep 17 00:00:00 2001 From: Rogee Date: Sun, 4 Oct 2026 16:37:45 +0800 Subject: [PATCH] feat(test): validate private SaaS snapshots before host startup --- deploys/test/nonprod-call-evidence.sh | 3 ++- deploys/test/saas-mock/README.md | 3 ++- deploys/test/saas-mock/main.go | 12 ++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/deploys/test/nonprod-call-evidence.sh b/deploys/test/nonprod-call-evidence.sh index 5948028..713525f 100755 --- a/deploys/test/nonprod-call-evidence.sh +++ b/deploys/test/nonprod-call-evidence.sh @@ -18,6 +18,7 @@ Options: --rtp-end PORT RTP range end (default: 10800). --preflight-only Start/stop capture and diagnostics without a call; do not require packets. --attempt-ledger FILE Daily trunk/number attempt ledger (default: /var/lib/sip-go-agent/state/real-call-attempts.tsv). + --proof-root DIR Live capture arm directory (default: /run/sip-go-agent/nonprod-armed). EOF exit 2 } @@ -68,7 +69,7 @@ while (($#)); do done case "$environment" in - development|mock|mixed|real) ;; + development|mock|mixed|real|nonprod-real) ;; production) echo 'production requires the separate production gate' >&2; exit 1 ;; *) echo 'invalid non-production environment' >&2; exit 1 ;; esac diff --git a/deploys/test/saas-mock/README.md b/deploys/test/saas-mock/README.md index 234e4c9..3aed5d0 100644 --- a/deploys/test/saas-mock/README.md +++ b/deploys/test/saas-mock/README.md @@ -1,6 +1,6 @@ # SaaS 侧测试模拟服务(非生产) -仅替代当前缺失的 SaaS,不改 Dispatcher 的正式 HTTP 配置接口或 MQ 归属。默认只提供静态配置和预建队列;另有**显式单次** `call.execute` 投递命令,绝不自动拨号或产生业务结果。 虚构的合同示例不能充当真实 AI、线路或任务授权。 +仅替代当前缺失的 SaaS,不改 Dispatcher 的正式 HTTP 配置接口或 MQ 归属。默认只提供静态配置和预建队列;另有**显式单次** `call.execute` 投递命令,绝不自动拨号或产生业务结果。虚构的合同示例不能充当真实 AI、线路或任务授权。 ## 数据 @@ -8,6 +8,7 @@ ## 运行 +- 可先以 `go run ./deploys/test/saas-mock --validate-only --data <私有目录> --dispatcher-id ` 离线校验快照;不连接 RabbitMQ/HTTPS。 - 事先建立专用空 RabbitMQ vhost,名称以 `saas-mock-` 开头;模拟服务只创建现行 durable 交换机、控制队列、每任务队列与结果队列并做精确绑定,不自动清理/覆盖已有消息。Dispatcher 自身仍只被动核验拓扑。 - 准备测试 HTTPS 证书与私钥;将 `SAAS_MOCK_DISPATCHER_SECRET` 和含凭据的 `SAAS_MOCK_RABBITMQ_URL` 放在受限环境文件,不在命令行、仓库或聊天中传输。 - 启动:`go run ./deploys/test/saas-mock --data <私有目录> --dispatcher-id --listen <地址:端口> --tls-cert <证书文件> --tls-key <私钥文件>`。 diff --git a/deploys/test/saas-mock/main.go b/deploys/test/saas-mock/main.go index 604c87a..0ab92f4 100644 --- a/deploys/test/saas-mock/main.go +++ b/deploys/test/saas-mock/main.go @@ -18,12 +18,24 @@ func main() { listen := flag.String("listen", "", "explicit HTTPS listen address") cert := flag.String("tls-cert", "", "HTTPS certificate file") key := flag.String("tls-key", "", "HTTPS private key file") + validateOnly := flag.Bool("validate-only", false, "validate private snapshots offline without MQ or HTTPS") publishID := flag.String("publish-event-id", "", "one-shot MQ event ID matching capture --call-id") publishTask := flag.String("publish-task-id", "", "one approved single-trunk task") publishCallee := flag.String("publish-callee", "", "one original allowlisted callee") flag.Parse() secret := os.Getenv("SAAS_MOCK_DISPATCHER_SECRET") brokerURL := os.Getenv("SAAS_MOCK_RABBITMQ_URL") + if *validateOnly { + if *dataDir == "" || *dispatcherID == "" || *publishID != "" || *publishTask != "" || *publishCallee != "" || flag.NArg() != 0 { + log.Fatal("offline validation requires only a private data directory and bound Dispatcher ID") + } + data, err := loadDataset(*dataDir, *dispatcherID) + if err != nil { + log.Fatal(err) + } + log.Printf("private SaaS snapshots validated: task_count=%d", len(data.tasks)) + return + } if *publishID != "" || *publishTask != "" || *publishCallee != "" { if *dataDir == "" || *dispatcherID == "" || brokerURL == "" || *publishID == "" || *publishTask == "" || *publishCallee == "" || flag.NArg() != 0 { log.Fatal("one-shot publish requires private data, dispatcher ID, MQ environment and explicit event/task/callee")