fix(secret_vault): prepare_command补齐env引用形态注入(2026-09-17 e2e实锤缺口)——SECRET_PROMPT_BLOCK承诺'命令写$PIPELINE_SEC_X执行瞬间注入真值'但实现只认@@sec:占位符,agent照prompt写env引用时hits空→env不注入→变量展开为空(实测stdout SEC_READY_空值);现两形态等价:存在名进hits注入,不存在名进unknown拒绝执行(同陷阱C绝不静默空值)

This commit is contained in:
ymq 2026-09-17 18:04:12 +08:00
parent 761052a298
commit 2607176cb7

View File

@ -775,6 +775,10 @@ async def sanitize_tool_output(sor, text: str, *, org_id: str = "",
# ══════════════════════ 执行边界:占位符 → 环境变量 ══════════════════════
#: env 引用形态($PIPELINE_SEC_NAME / ${PIPELINE_SEC_NAME}——prompt 承诺的写法
_ENV_REF_RE = re.compile(r"\$\{?" + ENV_PREFIX + r"([A-Z][A-Z0-9_]*)\}?")
async def prepare_command(sor, command: str, *, org_id: str = "",
user_id: str = "") -> Tuple[str, Dict[str, str], List[str]]:
"""执行边界唯一入口:命令里的占位符 → `$PIPELINE_SEC_NAME` + 环境变量字典。
@ -794,6 +798,19 @@ async def prepare_command(sor, command: str, *, org_id: str = "",
logger.warning("prepare_command load failed: %s", str(e)[:120])
secrets = {}
rewritten, hits, unknown = detokenize(command, secrets, mode="env")
# env 引用形态补齐2026-09-17 缺口修复e2e 实锤SECRET_PROMPT_BLOCK 承诺
# 「命令里写 $PIPELINE_SEC_X 平台执行瞬间注入真值」,但此前只认占位符形态——
# agent 照 prompt 写 env 引用时 hits 为空 → env 不注入 → 变量展开为空
# (实测 stdout `SEC_READY_` 空值)。两种写法从此等价:
# 已存在名称 → 进 hitsenv 注入);不存在名称 → 进 unknown拒绝执行
# 与陷阱 C「绝不静默空值」同原则——空展开会静默改变命令语义
for m in _ENV_REF_RE.finditer(rewritten):
n = m.group(1)
if n in secrets:
if n not in hits:
hits.append(n)
elif n not in unknown:
unknown.append(n)
env = resolve_env(secrets, hits)
if hits:
try: