From 0c6eed7539545068732aa49f92f6da29bdeec128 Mon Sep 17 00:00:00 2001 From: sunlei Date: Fri, 26 Jun 2026 18:05:19 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20=E4=BF=AE=E5=A4=8DNapCat=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E9=95=9C=E5=83=8F=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- ...T-NapCatQQ-Runtime-Image-Build.Jenkinsfile | 23 ++++++++++++++++++- src/selfTest.ts | 11 +++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 68cbc64..c73b480 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login - `ci/jenkins/KT-NapCatQQ-Upstream-Sync.Jenkinsfile` 是 NapCatQQ 上游审计入口,默认只调用 ktWorkflow 的 `napcat-upstream-audit` dry-run,保留人工审查边界。 - Codex 上游审计必须同时设置 `RUN_CODEX_AUDIT=true` 并填写 `CONFIRM_CODEX_WORKSPACE_WRITE=RUN_CODEX_WORKSPACE_WRITE_AUDIT`;这是因为 Codex runner 使用 workspace-write sandbox,不能作为定时任务默认行为。 - `ci/jenkins/KT-NapCatQQ-Runtime-Release.Jenkinsfile` 是运行时发布入口,先调用 `napcat-runtime-release-readiness`,再通过显式参数触发运行时镜像构建和 API promotion;下游 job 使用白名单 choice,避免任意 Jenkins job 名被传入,并把 upstream release commit / NapCat base image digest 透传到镜像构建证据。 -- `ci/jenkins/KT-NapCatQQ-Runtime-Image-Build.Jenkinsfile` 是运行时镜像构建下游,只从 NAS 本地裸仓库 clone 经过审查的 NapCatQQ fork ref,构建 `NapCat.Shell`,调用 API 仓库 `scripts/napcat-desktop-cn-stage-build.mjs` 生成 staged context,执行 `docker build` 和容器内 `/ci/napcat-desktop-cn/verify.sh`;它不触发 API promotion、不执行 `kubectl`、不合并或推送 Git。 +- `ci/jenkins/KT-NapCatQQ-Runtime-Image-Build.Jenkinsfile` 是运行时镜像构建下游,只从 NAS 本地裸仓库 clone 经过审查的 NapCatQQ fork ref,构建 `NapCat.Shell`,先要求 NAS API 工作区 clean,并从 Jenkins API main checkout 的只读 `.git` reference 做 `fetch + merge --ff-only`,再调用 API 仓库 `scripts/napcat-desktop-cn-stage-build.mjs` 生成 staged context,执行 `docker build` 和容器内 `/ci/napcat-desktop-cn/verify.sh`;由于该下游需要访问挂载的宿主 Docker socket,内层 runner 固定 `--user 0:0`,镜像验证容器按账号容器同款 `SYS_ADMIN` / seccomp / apparmor 参数和 `NAPCAT_REQUIRE_DEVICE_PROFILE=1` 启动,但它不触发 API promotion、不执行 `kubectl`、不合并或推送 Git。 - 生产 API promotion 除了 `PROMOTE_API_RUNTIME=true` 和明确 image/profile 参数外,还必须填写 `CONFIRM_API_PROMOTION_TARGET=PROMOTE_KT_TEMPLATE_API_MAIN`。 - 三个模板默认使用 NAS 工作区 `/vol1/docker/kt-codex/workspace/KT`,运行证据落在 `/vol1/docker/kt-codex/artifacts` 下。 - 模板只保存入口和参数形状,不记录 Jenkins credential、Token、SSH key 或其他真实凭据。 diff --git a/ci/jenkins/KT-NapCatQQ-Runtime-Image-Build.Jenkinsfile b/ci/jenkins/KT-NapCatQQ-Runtime-Image-Build.Jenkinsfile index 00479c2..763de95 100644 --- a/ci/jenkins/KT-NapCatQQ-Runtime-Image-Build.Jenkinsfile +++ b/ci/jenkins/KT-NapCatQQ-Runtime-Image-Build.Jenkinsfile @@ -22,6 +22,8 @@ pipeline { environment { KT_WORKSPACE_ROOT = '/vol1/docker/kt-codex/workspace/KT' API_ROOT = '/vol1/docker/kt-codex/workspace/KT/Node/kt-template-online-api' + API_GIT_REFERENCE_HOST = '/vol1/docker/volumes/kt-node-agent-workdir/_data/workspace/KT-Template_KT-Template-API_main/.git' + API_GIT_REFERENCE = '/ci/kt-template-online-api-main.git' NAPCAT_GIT_REPOSITORY = '/vol1/docker/kt-codex/git/NapCatQQ.git' KT_WORKFLOW_RUNNER_IMAGE = 'kt-jenkins-node-agent:current' } @@ -51,6 +53,7 @@ pipeline { set -e docker run --rm \ -e API_ROOT="$API_ROOT" \ + -e API_GIT_REFERENCE="$API_GIT_REFERENCE" \ -e BUILD_TAG="$BUILD_TAG" \ -e BUILD_URL="$BUILD_URL" \ -e COREPACK_HOME=/vol1/docker/kt-codex/runtime/corepack \ @@ -64,7 +67,9 @@ pipeline { -e UPSTREAM_RELEASE_COMMIT="$UPSTREAM_RELEASE_COMMIT" \ -e UPSTREAM_RELEASE_TAG="$UPSTREAM_RELEASE_TAG" \ -v /vol1/docker/kt-codex:/vol1/docker/kt-codex \ + -v "$API_GIT_REFERENCE_HOST":"$API_GIT_REFERENCE":ro \ -v /var/run/docker.sock:/var/run/docker.sock \ + --user 0:0 \ --entrypoint bash "$KT_WORKFLOW_RUNNER_IMAGE" -lc ' set -euo pipefail source /vol1/docker/kt-codex/runtime/nvm/nvm.sh @@ -91,8 +96,19 @@ pipeline { trap cleanup EXIT git config --global --add safe.directory "$NAPCAT_GIT_REPOSITORY" + git config --global --add safe.directory "$API_ROOT" rm -rf "$ARTIFACT_DIR" "$BUILD_WORKDIR" mkdir -p "$ARTIFACT_DIR" "$BUILD_WORKDIR" + if [ -n "$(git -C "$API_ROOT" status --short)" ]; then + echo "API_ROOT must be clean before runtime image build: $API_ROOT" >&2 + git -C "$API_ROOT" status --short >&2 + exit 2 + fi + test -d "$API_GIT_REFERENCE" + git -C "$API_ROOT" fetch "$API_GIT_REFERENCE" refs/remotes/origin/main + git -C "$API_ROOT" checkout main + git -C "$API_ROOT" merge --ff-only FETCH_HEAD + git -C "$API_ROOT" rev-parse HEAD > "$ARTIFACT_DIR/api-root-commit.txt" git clone "$NAPCAT_GIT_REPOSITORY" "$NAPCAT_ROOT" cd "$NAPCAT_ROOT" git checkout --detach "$NAPCAT_FORK_REF" @@ -118,7 +134,12 @@ pipeline { -t "$QQBOT_NAPCAT_IMAGE_OVERRIDE" \ -f "$STAGE_OUT/ci/napcat-desktop-cn/Dockerfile" \ "$STAGE_OUT" - docker run -d --name "$VERIFY_NAME" "$QQBOT_NAPCAT_IMAGE_OVERRIDE" >/dev/null + docker run -d --name "$VERIFY_NAME" \ + --cap-add SYS_ADMIN \ + --security-opt apparmor=unconfined \ + --security-opt seccomp=unconfined \ + -e NAPCAT_REQUIRE_DEVICE_PROFILE=1 \ + "$QQBOT_NAPCAT_IMAGE_OVERRIDE" >/dev/null sleep 3 docker exec "$VERIFY_NAME" sh /ci/napcat-desktop-cn/verify.sh docker image inspect "$QQBOT_NAPCAT_IMAGE_OVERRIDE" \ diff --git a/src/selfTest.ts b/src/selfTest.ts index 5600cd4..4e31e6d 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -811,6 +811,17 @@ export async function runSelfTest(): Promise { "requireRuntimeImageParameters(", "requireImageProfileMatch(", "-v /var/run/docker.sock:/var/run/docker.sock", + "--user 0:0", + "API_GIT_REFERENCE_HOST", + "API_GIT_REFERENCE", + "-v \"$API_GIT_REFERENCE_HOST\":\"$API_GIT_REFERENCE\":ro", + "--cap-add SYS_ADMIN", + "--security-opt apparmor=unconfined", + "--security-opt seccomp=unconfined", + "-e NAPCAT_REQUIRE_DEVICE_PROFILE=1", + "git -C \"$API_ROOT\" fetch \"$API_GIT_REFERENCE\" refs/remotes/origin/main", + "git -C \"$API_ROOT\" merge --ff-only FETCH_HEAD", + "\"$ARTIFACT_DIR/api-root-commit.txt\"", "git clone \"$NAPCAT_GIT_REPOSITORY\" \"$NAPCAT_ROOT\"", "BUILD_WORKDIR=\"$ARTIFACT_ROOT_REAL/runtime-image-build-workspace/$BUILD_ID_SAFE\"", "KT_ARTIFACT_ROOT must stay under /vol1/docker/kt-codex/artifacts",