From 7331323df47c81663c26d777a2a9be7dafed7d53 Mon Sep 17 00:00:00 2001 From: weichen Date: Tue, 13 Oct 2026 04:03:55 +0000 Subject: [PATCH] Give pin materialize the CI git channel and a private database Why: test-pg has no SSH known_hosts, and the shared agent_test database already holds another instance identity. Evidence: SELF python3 -m unittest tests.test_ci_credentials.CheckoutTests.test_rdm_pin_fetch_is_three_shas_on_the_allowlist tests.integration.lifecycle.test_lifecycle_real (1 pass, 24 skip). Impact: lifecycle children forward GIT_CONFIG_* only; serve stays env -i. Login and rdm.ping stay NOT_RUN. Refs: .task/feature-svc-d3-real-scenarios.md Co-authored-by: Cursor --- .gitea/workflows/ci.yaml | 6 +++++ scripts/svc.sh | 7 +++--- .../lifecycle/test_lifecycle_real.py | 25 +++++++++++++++++++ tests/test_ci_credentials.py | 5 ++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 362ddc17..f3a07667 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -447,14 +447,20 @@ jobs: - name: Real-combination lifecycle gate (make test-lifecycle, required) env: AGENT_PG_TEST_DSN: postgres://ci_agent:ci_job_local_only@127.0.0.1:5432/agent_test?sslmode=disable + SUBMODULE_TOKEN: ${{ secrets.SUBMODULE_TOKEN }} run: | set -euo pipefail # 路径变量在脚本内解析(YAML env: 不做 shell 展开)。 # 不设 SVC_RDM_ORIGIN:全轨 git 部署由 svc-realcombo 作业覆盖。 + # pins 物化没有 SSH known_hosts。token 只经 SVC_CI_GIT_TOKEN 进 + # ci_git_env 的 URL 级头,不写文件。 export SVC_TEST_REAL=1 SVC_TEST_PG=1 export SVC_REAL_BIN="$PWD/bin/agent-system" export SVC_REAL_RDM_BIN="$PWD/rdm/bin/agent-system-rdm" export SVC_RDM_SRC_DIR="$PWD/rdm" + export SVC_CI_GIT_SERVER="$(printf '%s' "$GITHUB_SERVER_URL" | sed 's:/*$::')" + export SVC_CI_GIT_TOKEN="$SUBMODULE_TOKEN" + unset SUBMODULE_TOKEN make test-lifecycle # U3(统一部署方案):真实 Dev/RDM 制品的 svc.sh 生命周期门禁——桩套件 diff --git a/scripts/svc.sh b/scripts/svc.sh index 411eec14..25380a94 100755 --- a/scripts/svc.sh +++ b/scripts/svc.sh @@ -1435,8 +1435,9 @@ svc_launch_serve() { } # svc_lifecycle_child ACTION [extra args...]:用清空的环境拉起本脚本的 -# __lifecycle。白名单:PATH/HOME/USER/LOGNAME/LANG/LC_*/TZ/TMPDIR、代理、SVC_*。 -# 从不传入 AGENT_SYSTEM_*。 +# __lifecycle。白名单:PATH/HOME/USER/LOGNAME/LANG/LC_*/TZ/TMPDIR、代理、SVC_*、 +# GIT_CONFIG_*(运行器把 SSH pin 改写成受信 HTTPS,token 只在环境里)。 +# 从不传入 AGENT_SYSTEM_*。serve 仍是 env -i,不继承这些变量。 svc_lifecycle_child() { local -a args=(env -i "PATH=${PATH:-/usr/bin:/bin}" "HOME=${HOME:-/tmp}" "USER=${USER:-}" "LOGNAME=${LOGNAME:-${USER:-}}" "LANG=${LANG:-C.UTF-8}" @@ -1450,7 +1451,7 @@ svc_lifecycle_child() { while IFS= read -r k; do [ -n "$k" ] || continue args+=("$k=${!k}") - done < <(compgen -e | grep -E '^(SVC_|LC_)' || true) + done < <(compgen -e | grep -E '^(SVC_|LC_|GIT_CONFIG_)' || true) if [ -n "${RDM_DISABLE_EXEC_TOOLS:-}" ]; then args+=("RDM_DISABLE_EXEC_TOOLS=$RDM_DISABLE_EXEC_TOOLS") fi diff --git a/tests/integration/lifecycle/test_lifecycle_real.py b/tests/integration/lifecycle/test_lifecycle_real.py index db1d2829..d0569726 100644 --- a/tests/integration/lifecycle/test_lifecycle_real.py +++ b/tests/integration/lifecycle/test_lifecycle_real.py @@ -15,8 +15,14 @@ import time import unittest import urllib.error import urllib.request +from urllib.parse import urlparse, urlunparse from pathlib import Path +from tests.test_svc_realcombo import ci_git_env +from urllib.parse import urlparse, urlunparse + +from tests.test_svc_realcombo import ci_git_env + SOURCE = Path(__file__).resolve().parents[3] PIN = Path(__file__).resolve().parent / "rdm.pin" @@ -55,6 +61,7 @@ class LifecycleRealTests(tsr.SvcAutoRecoverTests): self.pin = load_pin() self.env["SVC_RDM_SRC_DIR"] = SRC self.env["RDM_DISABLE_EXEC_TOOLS"] = "1" + self.env.update(ci_git_env()) self.env.pop("AGENT_SYSTEM_DSN", None) self.env.pop("AGENT_SYSTEM_DATA", None) @@ -516,6 +523,7 @@ class LifecycleRealTests(tsr.SvcAutoRecoverTests): dsn = os.environ.get("AGENT_PG_TEST_DSN", "") if not dsn: self.skipTest("PG 跨实例 NOT_RUN:未设置 AGENT_PG_TEST_DSN") + dsn = self.private_pg_dsn(dsn) port = self.free_port() self.seed_established("pga", port) self.svc("pga", "stop") @@ -572,6 +580,23 @@ class LifecycleRealTests(tsr.SvcAutoRecoverTests): self.assertNotIn(sentinel, text, path) self.svc("cred", "stop") + def private_pg_dsn(self, dsn): + """共享的 AGENT_PG_TEST_DSN 已被其他用例写入身份。本用例单独建库。""" + parsed = urlparse(dsn) + name = "d3pg_" + hashlib.sha256(os.urandom(8)).hexdigest()[:12] + created = subprocess.run( + ["psql", dsn, "-v", "ON_ERROR_STOP=1", "-c", + 'CREATE DATABASE "%s"' % name], + text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=30) + self.assertEqual(created.returncode, 0, created.stdout.replace(dsn, "")) + self.addCleanup(self.drop_private_pg, dsn, name) + return urlunparse(parsed._replace(path="/" + name)) + + def drop_private_pg(self, dsn, name): + subprocess.run( + ["psql", dsn, "-c", 'DROP DATABASE IF EXISTS "%s" WITH (FORCE)' % name], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=30) + def event_count(self, name): db = self.runtime(name) / "data" / "rdm.db" con = sqlite3.connect("file:%s?mode=ro" % db, uri=True) diff --git a/tests/test_ci_credentials.py b/tests/test_ci_credentials.py index 6f6fb350..e29b24b9 100644 --- a/tests/test_ci_credentials.py +++ b/tests/test_ci_credentials.py @@ -286,6 +286,11 @@ class CheckoutTests(unittest.TestCase): digests = (work / "rdm" / "pin-build-digests.txt").read_text() for sha in shas: self.assertIn(sha, digests) + gate = WORKFLOW.read_text().split( + "Real-combination lifecycle gate", 1)[1].split("\n svc-realcombo:", 1)[0] + self.assertIn('export SVC_CI_GIT_TOKEN="$SUBMODULE_TOKEN"', gate) + self.assertNotRegex(gate, r"(?m)^\s*source\s") + self.assertNotIn(">>", gate) if __name__ == "__main__":