From 2607176cb7eb5a7f0f22025bef57cf24b43ef412 Mon Sep 17 00:00:00 2001 From: ymq Date: Thu, 17 Sep 2026 18:04:12 +0800 Subject: [PATCH] =?UTF-8?q?fix(secret=5Fvault):=20prepare=5Fcommand?= =?UTF-8?q?=E8=A1=A5=E9=BD=90env=E5=BC=95=E7=94=A8=E5=BD=A2=E6=80=81?= =?UTF-8?q?=E6=B3=A8=E5=85=A5(2026-09-17=20e2e=E5=AE=9E=E9=94=A4=E7=BC=BA?= =?UTF-8?q?=E5=8F=A3)=E2=80=94=E2=80=94SECRET=5FPROMPT=5FBLOCK=E6=89=BF?= =?UTF-8?q?=E8=AF=BA'=E5=91=BD=E4=BB=A4=E5=86=99$PIPELINE=5FSEC=5FX?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E7=9E=AC=E9=97=B4=E6=B3=A8=E5=85=A5=E7=9C=9F?= =?UTF-8?q?=E5=80=BC'=E4=BD=86=E5=AE=9E=E7=8E=B0=E5=8F=AA=E8=AE=A4@@sec:?= =?UTF-8?q?=E5=8D=A0=E4=BD=8D=E7=AC=A6,agent=E7=85=A7prompt=E5=86=99env?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E6=97=B6hits=E7=A9=BA=E2=86=92env=E4=B8=8D?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E2=86=92=E5=8F=98=E9=87=8F=E5=B1=95=E5=BC=80?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA(=E5=AE=9E=E6=B5=8Bstdout=20SEC=5FREADY=5F?= =?UTF-8?q?=E7=A9=BA=E5=80=BC);=E7=8E=B0=E4=B8=A4=E5=BD=A2=E6=80=81?= =?UTF-8?q?=E7=AD=89=E4=BB=B7:=E5=AD=98=E5=9C=A8=E5=90=8D=E8=BF=9Bhits?= =?UTF-8?q?=E6=B3=A8=E5=85=A5,=E4=B8=8D=E5=AD=98=E5=9C=A8=E5=90=8D?= =?UTF-8?q?=E8=BF=9Bunknown=E6=8B=92=E7=BB=9D=E6=89=A7=E8=A1=8C(=E5=90=8C?= =?UTF-8?q?=E9=99=B7=E9=98=B1C=E7=BB=9D=E4=B8=8D=E9=9D=99=E9=BB=98?= =?UTF-8?q?=E7=A9=BA=E5=80=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pipeline_service/secret_vault.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pipeline_service/secret_vault.py b/pipeline_service/secret_vault.py index c627152..26faf77 100644 --- a/pipeline_service/secret_vault.py +++ b/pipeline_service/secret_vault.py @@ -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_` 空值)。两种写法从此等价: + # 已存在名称 → 进 hits(env 注入);不存在名称 → 进 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: