diff --git a/.github/scripts/ci-runner-routing.test.mjs b/.github/scripts/ci-runner-routing.test.mjs index c5a4e1a330e..fc8f2e22bb9 100644 --- a/.github/scripts/ci-runner-routing.test.mjs +++ b/.github/scripts/ci-runner-routing.test.mjs @@ -1707,6 +1707,8 @@ describe('manual Linux unit container PoC', () => { assert.match(driver.run, /image_context/); assert.doesNotMatch(driver.run, /docker build --file -/); assert.match(driver.run, /^FROM node:22-bookworm$/m); + assert.match(driver.run, /apt-get install -y --no-install-recommends jq /); + assert.match(driver.run, /jq --version/); assert.equal(driver.env.POC_SHA, '${{ github.event.inputs.branch_ref }}'); assert.doesNotMatch(driver.run, /2905dccbe45ed2917b28c7de6a935d031546ee43/); for (const fragment of [ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6343f39f59c..22246aa97ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -498,7 +498,7 @@ jobs: image_context="$(mktemp -d "${RUNNER_TEMP}/qwen-unit-poc-image-XXXXXX")" cat > "${image_context}/Dockerfile" <<'IMAGE' FROM node:22-bookworm - RUN apt-get update && apt-get install -y --no-install-recommends tmux zip unzip util-linux && rm -rf /var/lib/apt/lists/* + RUN apt-get update && apt-get install -y --no-install-recommends jq tmux zip unzip util-linux && rm -rf /var/lib/apt/lists/* IMAGE docker build --file "${image_context}/Dockerfile" --tag "${POC_IMAGE}" "${image_context}" rm -rf -- "${image_context}" @@ -536,6 +536,7 @@ jobs: } ' node -e 'if (process.versions.node.split(".")[0] !== "22") process.exit(1)' + jq --version for endpoint in 169.254.169.254 100.100.100.200; do code="$(curl --connect-timeout 2 --max-time 3 -sS -o /dev/null -w '%{http_code}' "http://${endpoint}/latest/meta-data/" || true)" case "${code}" in diff --git a/docs/design/2026-11-07-linux-unit-container-poc.md b/docs/design/2026-11-07-linux-unit-container-poc.md index 5a088ee2c9f..397e42e386e 100644 --- a/docs/design/2026-11-07-linux-unit-container-poc.md +++ b/docs/design/2026-11-07-linux-unit-container-poc.md @@ -52,9 +52,9 @@ When `linux_unit_container=true`: 1. The trusted classifier selects `docs_only` for the ordinary full-CI payload, so the unrelated existing jobs do not execute their full test bodies. 2. `linux_unit_poc` validates the repository format and exact SHA, checks out into a unique run/attempt subdirectory, disables credential persistence, and verifies the actual checked-out commit and absence of a local GitHub authentication header. -3. A trusted inline Dockerfile extends `node:22-bookworm` with the required tmux/zip/util-linux tools. It does not read any context or instructions from the tested checkout. +3. A trusted inline Dockerfile extends `node:22-bookworm` with jq, tmux/zip/unzip, and util-linux. It does not read any context or instructions from the tested checkout. 4. The driver uses `docker create` with `--init`, `--user node`, `--cap-drop ALL`, `--security-opt=no-new-privileges`, and a single read-only source mount. It supplies no privileged mode, no host network, no Docker socket, no base workspace mount, and no secret-bearing environment. -5. Before executing source scripts, the container checks `NoNewPrivs=1`, absence of effective `SYS_ADMIN`, `SYS_PTRACE`, `NET_ADMIN`, and `DAC_OVERRIDE`, absence of the Docker socket, Node 22, and blocked or explicitly denied AWS/Alibaba Cloud metadata endpoints. +5. Before executing source scripts, the container checks `NoNewPrivs=1`, absence of effective `SYS_ADMIN`, `SYS_PTRACE`, `NET_ADMIN`, and `DAC_OVERRIDE`, absence of the Docker socket, Node 22, and blocked or explicitly denied AWS/Alibaba Cloud metadata endpoints. It also verifies jq is installed. 6. The source is copied from `/source:ro` to `/tmp/repository`. Frozen pnpm installation, `npm run build`, `npm run bundle`, and the complete test-lane script execute as UID 1000 with a fresh HOME/Corepack cache and empty model credentials. Only the expected SHA is forwarded explicitly to the test container. 7. An `EXIT` trap force-removes the container and its volumes. A subsequent `docker ps --all` check proves it is gone, and a guarded final step removes the dedicated checkout. diff --git a/docs/design/2026-11-07-linux-unit-container-poc.zh-CN.md b/docs/design/2026-11-07-linux-unit-container-poc.zh-CN.md index f709e6b036a..ab48293effe 100644 --- a/docs/design/2026-11-07-linux-unit-container-poc.zh-CN.md +++ b/docs/design/2026-11-07-linux-unit-container-poc.zh-CN.md @@ -52,9 +52,9 @@ dispatch 版本在被测 checkout 存在前确定 workflow 定义。被测仓库 1. 可信分类器为普通全量 CI 负载选择 `docs_only`,避免其他既有 job 执行相应测试主体。 2. `linux_unit_poc` 校验仓库格式与完整 SHA,在唯一 run/attempt 子目录检出,禁用凭据持久化,并验证实际提交及本地 GitHub 认证 header 不存在。 -3. 可信内联 Dockerfile 在 `node:22-bookworm` 上安装 tmux/zip/util-linux 工具,不读取被测 checkout 的上下文或指令。 +3. 可信内联 Dockerfile 在 `node:22-bookworm` 上安装 jq、tmux/zip/util-linux 工具,不读取被测 checkout 的上下文或指令。 4. 驱动执行 `docker create`,使用 `--init`、`--user node`、`--cap-drop ALL`、`--security-opt=no-new-privileges`,且仅将指定源码目录只读挂载。禁用 privileged、宿主网络、Docker socket、基 workspace 挂载及携带 secret 的环境。 -5. 执行源码脚本前,容器检查 `NoNewPrivs=1`、有效 capability 不含 `SYS_ADMIN`、`SYS_PTRACE`、`NET_ADMIN`、`DAC_OVERRIDE`,无 Docker socket,Node 为 22,AWS/阿里云 metadata 不可达或被明确拒绝。 +5. 执行源码脚本前,容器检查 `NoNewPrivs=1`、有效 capability 不含 `SYS_ADMIN`、`SYS_PTRACE`、`NET_ADMIN`、`DAC_OVERRIDE`,无 Docker socket,Node 为 22,AWS/阿里云 metadata 不可达或被明确拒绝;并确认 jq 已安装。 6. 将 `/source:ro` 复制到 `/tmp/repository`,以 UID 1000、全新 HOME/Corepack 缓存及清空的模型凭据,安装锁定依赖,运行 `npm run build`、`npm run bundle` 和完整测试脚本。只有预期 SHA 被显式传入测试容器。 7. `EXIT` trap 强制删除容器及其卷,`docker ps --all` 复核容器已不存在,最后以受保护的步骤删除专用 checkout。