agent-exec transport 54fb3271bcec24c48fa8696f95200638/616960aa035d
This commit is contained in:
@@ -13,7 +13,7 @@ PLUGINS := plugins
|
||||
COMBO := core=$(shell git -C $(CORE) rev-parse --short HEAD 2>/dev/null)+backend=$(shell git -C $(BACKEND) rev-parse --short HEAD 2>/dev/null)+frontend=$(shell git -C $(FRONTEND) rev-parse --short HEAD 2>/dev/null)+ui=$(shell git -C $(UI) rev-parse --short HEAD 2>/dev/null)+agentcmd=$(shell git -C deps/agent-command rev-parse --short HEAD 2>/dev/null)+documents=$(shell git -C modules/documents rev-parse --short HEAD 2>/dev/null)+native=$(shell git -C deps/agent-native rev-parse --short HEAD 2>/dev/null)+squad=$(shell git -C deps/agent-squad rev-parse --short HEAD 2>/dev/null)+intent=$(shell git -C deps/agent-intent rev-parse --short HEAD 2>/dev/null)
|
||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null)+$(COMBO)
|
||||
|
||||
.PHONY: help sync status build frontend svc svc-list svc-info svc-commits svc-history svc-update svc-recover svc-watchdog test-backend test-backend-pg test-multi-instance test-lifecycle test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-triage task-triage-decide task-start task-resume task-sync task-close task-finish task-pr-check ci-wait facts-verify evidence version agent-exec-validate agent-exec-apply agent-exec-admit
|
||||
.PHONY: help sync status build frontend svc svc-list svc-info svc-commits svc-history svc-update svc-recover svc-watchdog test-backend test-backend-pg test-multi-instance test-lifecycle test-regulations-kb test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-triage task-triage-decide task-start task-resume task-sync task-close task-finish task-pr-check ci-wait facts-verify evidence version agent-exec-validate agent-exec-apply agent-exec-admit
|
||||
|
||||
version:
|
||||
@echo "agent-system $(VERSION)"
|
||||
@@ -87,6 +87,7 @@ help:
|
||||
@echo "make build 构建单二进制 bin/agent-system(契约同步→前端构建→embed→静态链接)"
|
||||
@echo "make test 全量测试(boundaries + pins + libs + core + backend + frontend + ui + agent-command)"
|
||||
@echo "make test-governance 临时真实仓库中的任务、证据、写守卫与 CI 凭据回归"
|
||||
@echo "make test-regulations-kb 法规知识库组合门禁:需 KBREG_TEST_DATABASE_URL、SVC_RDM_SRC_DIR、KB_SRC_DIR(不纳入 make test)"
|
||||
@echo "make svc 服务级操作:make svc ENV=<name> [ACTION=deploy|start|stop|restart|status|logs] [ARGS='--from dev@<sha> --tag ...']"
|
||||
@echo "make svc-list 服务总览:make svc-list [ARGS='--tag core'];数据库运维:scripts/svc.sh db create|dsn|backup|backups|restore|clone|copy|ls|set"
|
||||
@echo "make svc-info 综合信息报告(只读):make svc-info [ARGS='pg1 --reveal']——运行服务/数据库实例与内部库/配置快照"
|
||||
@@ -164,6 +165,14 @@ test-lifecycle:
|
||||
bash scripts/fetch-rdm-pin.sh tests/integration/lifecycle/rdm.pin >/dev/null
|
||||
python3 tests/integration/lifecycle/lifecycle_suite.py
|
||||
|
||||
# 法规知识库组合门禁(U8):固定 RDM/KB 修订上的 KB test-pg、RDM kbreg 与客户端制品凭据扫描。
|
||||
# 缺环境直接失败,不静默跳过;不纳入 make test。见 tests/integration/regulations-kb/README.md。
|
||||
test-regulations-kb:
|
||||
@test -n "$${KBREG_TEST_DATABASE_URL}" || { echo "test-regulations-kb: KBREG_TEST_DATABASE_URL 未设置(一次性 PostgreSQL+pgvector 必需,不静默跳过)"; exit 1; }
|
||||
@test -n "$${SVC_RDM_SRC_DIR}" || { echo "test-regulations-kb: SVC_RDM_SRC_DIR 未设置(RDM 检出必需,不静默跳过)"; exit 1; }
|
||||
@test -n "$${KB_SRC_DIR}" || { echo "test-regulations-kb: KB_SRC_DIR 未设置(KB-Regulations 检出必需,不静默跳过)"; exit 1; }
|
||||
bash tests/integration/regulations-kb/run.sh
|
||||
|
||||
# 双进程 HTTP 级验收(协作存储方案 U7):两个真实 serve 进程共享隔离 PG。
|
||||
# 缺环境时明确失败而非静默跳过;见 tests/integration/multi-instance/README.md。
|
||||
test-multi-instance:
|
||||
|
||||
+16
@@ -82,3 +82,19 @@ U2 起实施与部署分别评审。
|
||||
- [渐进工作台界面重设计 r0.2](modules/documents/docs/proposals/2026-10-12-work-companion-ui-design.md):用户已授权连续实施;[计划 r1](modules/documents/docs/proposals/2026-10-12-work-companion-ui-plan.md)覆盖任务摘要、对话/输入、窄屏和真实状态投影;进展见对应任务卡。
|
||||
|
||||
- [系统项目、成员工作入口与私域协作闭环 r1](modules/documents/docs/proposals/2026-10-13-system-project-membership.md):2026-10-13 用户批准阶段 1–9 连续推进;统一全局项目身份与名称、成员个人会话、每项目两树一网和私域权限;当前组合验证/CI/tag 消费推进中,部署与线上修复未授权。
|
||||
|
||||
## 法规知识库组合
|
||||
|
||||
[法规知识库计划](docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md) U8 的固定组合:
|
||||
|
||||
- `modules/backend` 56a7f9f(EXT-20 法规检索/搜索扩展合同)、`modules/documents` 5bb4877(EXT-20 提案)、
|
||||
`modules/frontend` 50ec836 与 `modules/ui` 5c2b103(法规引用渲染)。
|
||||
- RDM ece91da(含 kbreg 组合)与 KB-Regulations 5dddad2,固定在
|
||||
`tests/integration/regulations-kb/components.pin`;KB 经 RDM 的 `pins/agent-system-kb-regulations`
|
||||
gitlink 接入,门禁要求该 gitlink 是 `kb_sha` 的祖先。
|
||||
- 凭据变量:`KBREG_DATABASE_URL`、`KBREG_EMBED_API_KEY`、`KBREG_SEARCH_ZHIPU_API_KEY`、`KBREG_MINERU_TOKEN`
|
||||
(测试库用 `KBREG_TEST_DATABASE_URL`)。按环境注入、轮换与撤销见 KB 仓 `docs/operations/runbook.md`;值不入仓、不回显。
|
||||
- 门禁:`make test-regulations-kb`(需 `KBREG_TEST_DATABASE_URL`、`SVC_RDM_SRC_DIR`、`KB_SRC_DIR`,不纳入 `make test`),
|
||||
说明见 `tests/integration/regulations-kb/README.md`。真实搜索/嵌入/MinerU 调用 NOT_RUN,待 owner 批准。
|
||||
|
||||
部署、版本发布与业务/法务验收是后续独立门禁,本组合门禁通过不代表其中任何一项完成。
|
||||
|
||||
+1
-1
Submodule modules/backend updated: 276dd73824...56a7f9f440
+1
-1
Submodule modules/documents updated: e2f5729e8f...5bb487795c
+1
-1
Submodule modules/frontend updated: 92864db8d3...50ec83657a
+1
-1
Submodule modules/ui updated: c9187473fb...5c2b1036dd
@@ -0,0 +1,53 @@
|
||||
# 法规知识库组合门禁(U8)
|
||||
|
||||
在固定组件修订上验证 RDM + 法规知识库(KB-Regulations)的本地组合:数据与索引可恢复、
|
||||
双源与引用流程可用、凭据不进入客户端制品。对应
|
||||
[法规知识库计划](../../../docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md) 的 U8
|
||||
与 Verification Contract 的 Composition/recovery 行;引用对象见
|
||||
[法规引用合同](../../../docs/superpowers/specs/2026-10-18-regulations-citation-contract.md)。
|
||||
|
||||
## 固定组件
|
||||
|
||||
`components.pin` 只有两个键,均为 40 位 hex,`run.sh` 逐行解析、从不执行:
|
||||
|
||||
- `rdm_sha`:Agent-System-RDM main(含 U6、U7 与 kbreg 组合)。
|
||||
- `kb_sha`:Agent-System-KB-Regulations main(含 provider 与 U8 恢复测试)。
|
||||
|
||||
`run.sh` 先核对两个检出的 HEAD 等于 pin,再核对 RDM 检出中
|
||||
`pins/agent-system-kb-regulations` gitlink 是 KB 检出里 `kb_sha` 的祖先(RDM 编译所用 KB 代码包含在被测修订中)。
|
||||
Dev 侧 Backend/Documents/Frontend/UI 的 gitlink 由本仓 `modules/` 固定,见 PROJECT.md「法规知识库组合」。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- 一次性 PostgreSQL(带 pgvector),连接串放在 `KBREG_TEST_DATABASE_URL`;PATH 上有 `pg_dump`、`pg_restore`。
|
||||
可用 KB 仓 `scripts/test-pg-local.sh` 起临时库。门禁会写入该库,不要指向任何真实数据。
|
||||
- `SVC_RDM_SRC_DIR`:RDM 检出,位于 `rdm_sha`,submodule 已递归物化。
|
||||
- `KB_SRC_DIR`:KB-Regulations 检出,位于 `kb_sha`,submodule 已物化。
|
||||
- Go 与 Node(RDM 测试及客户端制品构建所需)。
|
||||
- 客户端制品扫描需要已构建的 RDM 产物(RDM 检出的 `bin/`、`.build/product/frontend/dist`),
|
||||
或用 `REGKB_SCAN_DIRS` 指定待扫目录(空格分隔)。
|
||||
|
||||
## 用法
|
||||
|
||||
```bash
|
||||
KBREG_TEST_DATABASE_URL=... SVC_RDM_SRC_DIR=/path/to/rdm KB_SRC_DIR=/path/to/kb \
|
||||
make test-regulations-kb
|
||||
```
|
||||
|
||||
缺任一变量时直接以非零退出并指出变量名,不运行任何阶段。每个阶段打印 `PASS <阶段>` 或
|
||||
`FAIL <阶段>`,任一失败则整体非零退出。脚本不回显 `KBREG_TEST_DATABASE_URL` 或任何凭据值。
|
||||
|
||||
## 各阶段证明什么
|
||||
|
||||
| 阶段 | 命令 | 对应 U8 场景 |
|
||||
|---|---|---|
|
||||
| `kb-test-pg` | `make -C "$KB_SRC_DIR" test-pg` | provider 组合链;dump/restore 后重建索引仍保持语料修订哈希与历史引用解析;provider/解析器不可用;凭据注入、轮换与撤销 |
|
||||
| `rdm-kbreg` | `GOWORK=off go test -count=1 ./plugins/kbreg/...`,以及 `-run 'Composed\|RegCite\|Citation\|RegCheck\|RegBatch\|RegAudit'` 覆盖 `./internal/rdmapp/...`、`./plugins/rdm/...` | 完整法规问答的双通道记录、条款引用与审计批次重放;缺一通道时报告降级而非双源通过;保密词留在本地;凭据不进入输出;审计封印校验 |
|
||||
| `client-asset-secret-scan` | 扫描 `REGKB_SCAN_DIRS`(缺省为 RDM 的 `bin/` 与 `.build/product/frontend/dist`) | 凭据不出现在客户端制品:任何文件含字符串 `KBREG_`,或含环境中非空 `KBREG_*KEY*`、`KBREG_*TOKEN*`、`KBREG_DATABASE_URL` 的值即失败;只打印文件路径与变量名。没有可扫目录时失败 |
|
||||
|
||||
跨项目与受限来源的拒绝/脱敏场景归入 `rdm-kbreg` 阶段所选的 RDM 命令总线测试;具体用例以固定 RDM 修订中的测试为准。
|
||||
|
||||
## 不在本门禁范围
|
||||
|
||||
- 真实网络搜索、嵌入与 MinerU 调用:NOT_RUN,待 owner 批准外部调用后另行执行。
|
||||
- 部署、版本发布与业务/法务验收:均为后续独立门禁,本门禁通过不代表其中任何一项完成。
|
||||
@@ -0,0 +1,6 @@
|
||||
# 法规知识库组合门禁的固定组件(U8)。只接受 rdm_sha、kb_sha 两个键,值为 40 位 hex。
|
||||
# run.sh 逐行解析本文件,不执行、不 source。升级走 PR。
|
||||
# rdm_sha:RDM main,含 U6、U7 与 kbreg 组合。
|
||||
# kb_sha:KB-Regulations main,含 provider 与 U8 恢复测试;须包含 RDM pins/agent-system-kb-regulations。
|
||||
rdm_sha=ece91dab9f23628be54a91e846389cb3753b88dd
|
||||
kb_sha=5dddad2ae58e7d0d7fffc95464e80fa0040d5e08
|
||||
Executable
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
# 法规知识库组合门禁(U8)。缺环境直接失败,不静默跳过。
|
||||
# 不回显任何 KBREG_* 值;扫描结果只打印文件路径与变量名。
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
pin="${REGKB_PIN:-$here/components.pin}"
|
||||
|
||||
# 与 scripts/fetch-rdm-pin.sh 同规则:只认已知键、40 位 hex,不执行 pin 文件。
|
||||
[ -f "$pin" ] || { echo "components.pin 不存在:$pin" >&2; exit 1; }
|
||||
declare -A got=()
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
case "$line" in
|
||||
''|\#*) continue ;;
|
||||
esac
|
||||
case "$line" in
|
||||
*=*) ;;
|
||||
*) echo "components.pin 行格式错误(须为 key=sha)" >&2; exit 1 ;;
|
||||
esac
|
||||
key="${line%%=*}"
|
||||
val="${line#*=}"
|
||||
case "$key" in
|
||||
rdm_sha|kb_sha) ;;
|
||||
*) echo "components.pin 未知键:$key" >&2; exit 1 ;;
|
||||
esac
|
||||
[[ "$val" =~ ^[0-9a-f]{40}$ ]] || { echo "components.pin 的 $key 不是 40 位 hex" >&2; exit 1; }
|
||||
[ -z "${got[$key]:-}" ] || { echo "components.pin 重复键:$key" >&2; exit 1; }
|
||||
got["$key"]="$val"
|
||||
done < "$pin"
|
||||
[ "${#got[@]}" -eq 2 ] || { echo "components.pin 必须同时有 rdm_sha、kb_sha" >&2; exit 1; }
|
||||
rdm_sha="${got[rdm_sha]}"
|
||||
kb_sha="${got[kb_sha]}"
|
||||
|
||||
missing=0
|
||||
for v in KBREG_TEST_DATABASE_URL SVC_RDM_SRC_DIR KB_SRC_DIR; do
|
||||
if [ -z "${!v:-}" ]; then
|
||||
echo "regulations-kb: $v 未设置(组合门禁必需,不静默跳过)" >&2
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
[ "$missing" -eq 0 ] || exit 2
|
||||
|
||||
rdm_dir="$SVC_RDM_SRC_DIR"
|
||||
kb_dir="$KB_SRC_DIR"
|
||||
|
||||
head_of() { git -C "$1" rev-parse --verify -q HEAD 2>/dev/null || true; }
|
||||
rdm_head="$(head_of "$rdm_dir")"
|
||||
[ "$rdm_head" = "$rdm_sha" ] || { echo "regulations-kb: SVC_RDM_SRC_DIR HEAD=${rdm_head:-<无>},须为 rdm_sha=$rdm_sha" >&2; exit 1; }
|
||||
kb_head="$(head_of "$kb_dir")"
|
||||
[ "$kb_head" = "$kb_sha" ] || { echo "regulations-kb: KB_SRC_DIR HEAD=${kb_head:-<无>},须为 kb_sha=$kb_sha" >&2; exit 1; }
|
||||
|
||||
kb_link="$(git -C "$rdm_dir" rev-parse --verify -q "HEAD:pins/agent-system-kb-regulations" 2>/dev/null || true)"
|
||||
[ -n "$kb_link" ] || { echo "regulations-kb: RDM 检出缺少 pins/agent-system-kb-regulations gitlink" >&2; exit 1; }
|
||||
if ! git -C "$kb_dir" merge-base --is-ancestor "$kb_link" "$kb_sha" 2>/dev/null; then
|
||||
echo "regulations-kb: RDM 的 KB gitlink $kb_link 不是 kb_sha=$kb_sha 的祖先(或 KB 检出缺该对象)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "regulations-kb: rdm=$rdm_sha kb=$kb_sha(RDM KB gitlink $kb_link 为其祖先)"
|
||||
|
||||
failed=0
|
||||
# 在 if 条件中 set -e 不生效:阶段函数内多条命令须显式 && 串联。
|
||||
stage() {
|
||||
local name="$1"; shift
|
||||
echo "=== stage $name ==="
|
||||
if ( "$@" ); then
|
||||
echo "PASS $name"
|
||||
else
|
||||
echo "FAIL $name"
|
||||
failed=1
|
||||
fi
|
||||
}
|
||||
|
||||
stage_kb() {
|
||||
make -C "$kb_dir" test-pg
|
||||
}
|
||||
|
||||
stage_rdm() {
|
||||
cd "$rdm_dir" &&
|
||||
GOWORK=off go test -count=1 ./plugins/kbreg/... &&
|
||||
GOWORK=off go test -count=1 -run 'Composed|RegCite|Citation|RegCheck|RegBatch|RegAudit' ./internal/rdmapp/... ./plugins/rdm/...
|
||||
}
|
||||
|
||||
stage_scan() {
|
||||
local dirs=() d
|
||||
if [ -n "${REGKB_SCAN_DIRS:-}" ]; then
|
||||
read -r -a dirs <<< "$REGKB_SCAN_DIRS"
|
||||
else
|
||||
for d in "$rdm_dir/bin" "$rdm_dir/.build/product/frontend/dist"; do
|
||||
[ -d "$d" ] && dirs+=("$d")
|
||||
done
|
||||
fi
|
||||
if [ "${#dirs[@]}" -eq 0 ]; then
|
||||
echo "scan: 没有可扫描的客户端制品目录(先构建 RDM 产品,或设置 REGKB_SCAN_DIRS)" >&2
|
||||
return 1
|
||||
fi
|
||||
local secret_vars=() name
|
||||
while IFS= read -r name; do
|
||||
case "$name" in
|
||||
KBREG_*KEY*|KBREG_*TOKEN*|KBREG_DATABASE_URL)
|
||||
[ -n "${!name:-}" ] && secret_vars+=("$name") ;;
|
||||
esac
|
||||
done < <(compgen -e)
|
||||
local tmp rc=0 hits f
|
||||
tmp="$(mktemp)" || return 1
|
||||
for d in "${dirs[@]}"; do
|
||||
if [ ! -d "$d" ]; then
|
||||
echo "scan: 目录不存在:$d" >&2
|
||||
rc=1
|
||||
continue
|
||||
fi
|
||||
echo "scan: $d"
|
||||
hits="$(grep -rlF -e 'KBREG_' -- "$d" || true)"
|
||||
if [ -n "$hits" ]; then
|
||||
while IFS= read -r f; do echo "scan: $f 含字符串 KBREG_" >&2; done <<< "$hits"
|
||||
rc=1
|
||||
fi
|
||||
for name in "${secret_vars[@]}"; do
|
||||
printf '%s\n' "${!name}" | grep -v '^$' > "$tmp" || true
|
||||
[ -s "$tmp" ] || continue
|
||||
hits="$(grep -rlF -f "$tmp" -- "$d" || true)"
|
||||
if [ -n "$hits" ]; then
|
||||
while IFS= read -r f; do echo "scan: $f 含 $name 的值" >&2; done <<< "$hits"
|
||||
rc=1
|
||||
fi
|
||||
done
|
||||
done
|
||||
rm -f "$tmp"
|
||||
echo "scan: 已核对 ${#secret_vars[@]} 个凭据变量:${secret_vars[*]:-<无>}"
|
||||
return "$rc"
|
||||
}
|
||||
|
||||
stage kb-test-pg stage_kb
|
||||
stage rdm-kbreg stage_rdm
|
||||
stage client-asset-secret-scan stage_scan
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo "regulations-kb: FAIL"
|
||||
exit 1
|
||||
fi
|
||||
echo "regulations-kb: PASS"
|
||||
@@ -0,0 +1,102 @@
|
||||
"""法规知识库组合门禁:components.pin 只接受固定 SHA;run.sh 缺环境直接失败。"""
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
GATE = ROOT / "tests" / "integration" / "regulations-kb"
|
||||
PIN = GATE / "components.pin"
|
||||
RUN = GATE / "run.sh"
|
||||
HEX40 = re.compile(r"^[0-9a-f]{40}$")
|
||||
KEYS = {"rdm_sha", "kb_sha"}
|
||||
REQUIRED = ("KBREG_TEST_DATABASE_URL", "SVC_RDM_SRC_DIR", "KB_SRC_DIR")
|
||||
|
||||
|
||||
def load_pin(text):
|
||||
out = {}
|
||||
for line in text.splitlines():
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" not in line:
|
||||
raise ValueError("bad pin line")
|
||||
key, value = line.split("=", 1)
|
||||
if key not in KEYS:
|
||||
raise ValueError("unknown pin key")
|
||||
if not HEX40.match(value):
|
||||
raise ValueError("sha must be 40 hex")
|
||||
if key in out:
|
||||
raise ValueError("duplicate pin key")
|
||||
out[key] = value
|
||||
if set(out) != KEYS:
|
||||
raise ValueError("pin keys incomplete")
|
||||
return out
|
||||
|
||||
|
||||
def run_gate(env, timeout=20):
|
||||
base = {"PATH": os.environ.get("PATH", "/usr/bin:/bin")}
|
||||
base.update(env)
|
||||
return subprocess.run(
|
||||
["bash", str(RUN)], cwd=ROOT, env=base, capture_output=True, text=True, timeout=timeout
|
||||
)
|
||||
|
||||
|
||||
class RegulationsKbPinTests(unittest.TestCase):
|
||||
def test_pin_is_two_fixed_shas(self):
|
||||
doc = load_pin(PIN.read_text())
|
||||
self.assertEqual(set(doc), KEYS)
|
||||
for value in doc.values():
|
||||
self.assertRegex(value, HEX40)
|
||||
|
||||
def test_parser_rejects_url_short_sha_and_unknown_key(self):
|
||||
kb = "kb_sha=" + "b" * 40 + "\n"
|
||||
bad = [
|
||||
"rdm_sha=https://example.invalid/repo.git\n" + kb,
|
||||
"rdm_sha=abc\n" + kb,
|
||||
"rdm_sha=" + "a" * 40 + "\n" + kb + "url=" + "c" * 40 + "\n",
|
||||
]
|
||||
for text in bad:
|
||||
with self.assertRaises(ValueError):
|
||||
load_pin(text)
|
||||
|
||||
def test_run_sh_parser_rejects_bad_pins_before_env_check(self):
|
||||
kb = "kb_sha=" + "b" * 40 + "\n"
|
||||
cases = {
|
||||
"rdm_sha=https://example.invalid/repo.git\n" + kb: "不是 40 位 hex",
|
||||
"rdm_sha=abc\n" + kb: "不是 40 位 hex",
|
||||
"rdm_sha=" + "a" * 40 + "\n" + kb + "url=" + "c" * 40 + "\n": "未知键",
|
||||
"rdm_sha=$(touch /tmp/regkb-pwned)\n" + kb: "不是 40 位 hex",
|
||||
kb: "必须同时有",
|
||||
}
|
||||
for text, expect in cases.items():
|
||||
with tempfile.NamedTemporaryFile("w", suffix=".pin", delete=False) as f:
|
||||
f.write(text)
|
||||
path = f.name
|
||||
try:
|
||||
proc = run_gate({"REGKB_PIN": path})
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertNotEqual(proc.returncode, 0, text)
|
||||
self.assertIn(expect, proc.stderr, text)
|
||||
self.assertNotIn("=== stage", proc.stdout)
|
||||
|
||||
def test_run_sh_names_each_missing_variable_without_running_stages(self):
|
||||
proc = run_gate({})
|
||||
self.assertNotEqual(proc.returncode, 0)
|
||||
for name in REQUIRED:
|
||||
self.assertIn(name, proc.stderr)
|
||||
self.assertNotIn("=== stage", proc.stdout)
|
||||
|
||||
for missing in REQUIRED:
|
||||
env = {n: "/nonexistent-fake" for n in REQUIRED if n != missing}
|
||||
proc = run_gate(env)
|
||||
self.assertNotEqual(proc.returncode, 0, missing)
|
||||
self.assertIn(missing + " 未设置", proc.stderr)
|
||||
self.assertNotIn("=== stage", proc.stdout)
|
||||
self.assertNotIn("/nonexistent-fake", proc.stdout + proc.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user