fix: isolate Gitea Python dependencies
Run Python tooling in repository virtual environments so xiaoxin respects the PEP 668 system package boundary.
This commit is contained in:
@@ -45,8 +45,10 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install -r requirements.txt -r requirements-dev.txt
|
||||
python3 -m venv .venv
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt -r requirements-dev.txt
|
||||
npm ci --prefix frontend
|
||||
- name: Validate backend, package, frontend, and database contracts
|
||||
env:
|
||||
@@ -54,11 +56,12 @@ jobs:
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: ci-placeholder
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ruff check scripts/run_quality_gate.py tests/test_varga_bphs.py tests/test_ashtakavarga_invariants.py tests/test_cli_smoke.py tests/test_yoga_rules_integrity.py
|
||||
python3 -m py_compile scripts/*.py jyotish_vedic/*.py mcp_server.py
|
||||
python3 scripts/run_quality_gate.py --profile quick --skip-yoga-logic --skip-frontend-runtime
|
||||
python3 scripts/commercial_privacy_artifact_scan.py --json
|
||||
python3 -m build
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
.venv/bin/ruff check scripts/run_quality_gate.py tests/test_varga_bphs.py tests/test_ashtakavarga_invariants.py tests/test_cli_smoke.py tests/test_yoga_rules_integrity.py
|
||||
.venv/bin/python -m py_compile scripts/*.py jyotish_vedic/*.py mcp_server.py
|
||||
.venv/bin/python scripts/run_quality_gate.py --profile quick --skip-yoga-logic --skip-frontend-runtime
|
||||
.venv/bin/python scripts/commercial_privacy_artifact_scan.py --json
|
||||
.venv/bin/python -m build
|
||||
npm test --prefix frontend
|
||||
npm run lint --prefix frontend
|
||||
npm run build --prefix frontend
|
||||
|
||||
@@ -31,14 +31,16 @@ jobs:
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: ci-placeholder
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install -r requirements.txt -r requirements-dev.txt
|
||||
python3 -m venv .venv
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt -r requirements-dev.txt
|
||||
npm ci --prefix frontend
|
||||
ruff check scripts/run_quality_gate.py tests/test_varga_bphs.py tests/test_ashtakavarga_invariants.py tests/test_cli_smoke.py tests/test_yoga_rules_integrity.py
|
||||
python3 -m py_compile scripts/*.py jyotish_vedic/*.py mcp_server.py
|
||||
python3 scripts/run_quality_gate.py --profile quick --skip-yoga-logic --skip-frontend-runtime
|
||||
python3 scripts/commercial_privacy_artifact_scan.py --json
|
||||
python -m py_compile scripts/*.py jyotish_vedic/*.py mcp_server.py
|
||||
python scripts/run_quality_gate.py --profile quick --skip-yoga-logic --skip-frontend-runtime
|
||||
python scripts/commercial_privacy_artifact_scan.py --json
|
||||
npm test --prefix frontend
|
||||
npm run lint --prefix frontend
|
||||
npm run build --prefix frontend
|
||||
python3 -m build
|
||||
python -m build
|
||||
|
||||
@@ -27,11 +27,17 @@ jobs:
|
||||
- name: Build and check package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 -m pip install build twine
|
||||
python3 -m build
|
||||
python3 -m twine check dist/*
|
||||
python3 -m venv .venv
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install build twine
|
||||
python -m build
|
||||
python -m twine check dist/*
|
||||
- name: Publish to PyPI
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
||||
run: python3 -m twine upload --skip-existing dist/*
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python -m twine upload --skip-existing dist/*
|
||||
|
||||
@@ -31,8 +31,10 @@ jobs:
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: ci-placeholder
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install -r requirements.txt -r requirements-dev.txt playwright
|
||||
python3 -m playwright install --with-deps chromium
|
||||
python3 -m venv .venv
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt -r requirements-dev.txt playwright
|
||||
python -m playwright install --with-deps chromium
|
||||
npm ci --prefix frontend
|
||||
python3 scripts/run_quality_gate.py --profile release
|
||||
python scripts/run_quality_gate.py --profile release
|
||||
|
||||
@@ -30,11 +30,13 @@ jobs:
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: ci-placeholder
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install -r requirements.txt -r requirements-dev.txt
|
||||
python3 -m venv .venv
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt -r requirements-dev.txt
|
||||
npm ci --prefix frontend
|
||||
python3 -m pytest -vv --maxfail=1
|
||||
python3 tests/run_all.py
|
||||
python -m pytest -vv --maxfail=1
|
||||
python tests/run_all.py
|
||||
npm test --prefix frontend
|
||||
npm run lint --prefix frontend
|
||||
npm run build --prefix frontend
|
||||
|
||||
@@ -1519,3 +1519,19 @@
|
||||
- 相关记录:无
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
## BUG-083 | Gitea xiaoxin Runner 向系统 Python 安装依赖触发 PEP 668
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-27
|
||||
- 最近更新:2026-07-27
|
||||
- 影响面:Gitea 后端质量门禁、CI、完整测试、发布质量门禁与 PyPI 发布
|
||||
- 用户现象:xiaoxin Runner 执行 `python3 -m pip install` 时以 `externally-managed-environment` 失败,工作流无法进入后续 Ruff、pytest、Playwright、构建或上传阶段。
|
||||
- 触发条件:基于启用 PEP 668 的系统 Python 运行任一包含 pip 安装的 `.gitea/workflows/*.yml`。
|
||||
- 根因:BUG-082 统一 Gitea Runner 与原生工具链时只审计了 runner、checkout、触发器和镜像主链,没有约束 Python 依赖隔离;五个工作流仍直接向 Runner 的系统 Python 执行 pip 安装,且 Gitea step 之间不会自动延续 shell 内的 PATH 修改。
|
||||
- 修复:所有包含 pip 安装的 Gitea workflow 都先创建仓库内 `.venv` 并在同一安装 step 显式将其 `bin` 目录置于 PATH;后续独立 Python step(包括后端验证与 PyPI 上传)再次显式设置同一 PATH。未使用 `--break-system-packages`,也未修改 GitHub workflows。
|
||||
- 验证:前端 Gitea workflow 契约测试枚举全部 `.gitea/workflows/*.yml`,确认五个 pip workflow 均创建并选择 `.venv`、后续 Python step 重新选择 `.venv`、不存在裸 `pip install` 或 `--break-system-packages`;全部 Gitea YAML 完成解析验证。
|
||||
- 防复发:工作流审计必须动态枚举全部 Gitea YAML;任何出现 pip install 的 workflow 都必须创建 `.venv`,任何随后执行 Python、Ruff、pytest、Playwright 或构建/上传命令的独立 step 都必须显式导出 venv PATH。
|
||||
- 相关记录:BUG-082
|
||||
- 复发自:BUG-082
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
@@ -420,6 +420,48 @@ test("all Gitea workflows use xiaoxin, native checkout, and safe triggers", () =
|
||||
assert.doesNotMatch(all, /GITEA_REGISTRY_USERNAME|GITEA_REGISTRY_TOKEN|git\.copse\.top\/root\/jyotisha-(?:api|web)/);
|
||||
});
|
||||
|
||||
test("Gitea workflows isolate pip installs and Python tooling in a virtualenv", () => {
|
||||
const names = readdirSync(giteaWorkflowDirectory)
|
||||
.filter((name) => name.endsWith(".yml"));
|
||||
const pipInstall = /(?:python3?\s+-m\s+)?pip3?\s+install/;
|
||||
const pythonTooling = /^\s+(?:python3?|ruff|pytest|playwright|build)(?:\s|$)/m;
|
||||
const expected = [
|
||||
"backend-quality-gate.yml",
|
||||
"ci.yml",
|
||||
"publish-pypi.yml",
|
||||
"release-quality-gate.yml",
|
||||
"test.yml",
|
||||
];
|
||||
const workflowsWithPip: string[] = [];
|
||||
|
||||
for (const name of names) {
|
||||
const workflow = read(new URL(name, giteaWorkflowDirectory));
|
||||
if (!pipInstall.test(workflow)) continue;
|
||||
workflowsWithPip.push(name);
|
||||
assert.doesNotMatch(workflow, /--break-system-packages/, name);
|
||||
assert.doesNotMatch(workflow, /^\s+pip3?\s+install/m, name);
|
||||
|
||||
const runBlocks = workflow.match(/^\s{8}run:\s*(?:\|\s*\n(?:\s{10}.*(?:\n|$))+|[^\n]+)$/gm) ?? [];
|
||||
let virtualenvCreated = false;
|
||||
for (const block of runBlocks) {
|
||||
const installsWithPip = pipInstall.test(block);
|
||||
if (installsWithPip) {
|
||||
assert.match(block, /python3 -m venv \.venv/, `${name}: pip step must create .venv`);
|
||||
virtualenvCreated = true;
|
||||
}
|
||||
if (virtualenvCreated && pythonTooling.test(block)) {
|
||||
assert.match(
|
||||
block,
|
||||
/export PATH="\$PWD\/\.venv\/bin:\$PATH"/,
|
||||
`${name}: every later Python step must select .venv`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(workflowsWithPip.sort(), expected);
|
||||
});
|
||||
|
||||
test("Gitea staging push validates once then publishes and deploys immutable ACR images", () => {
|
||||
const workflow = read(giteaQualityWorkflow);
|
||||
assert.match(workflow, /publish-and-deploy:[\s\S]*needs: validate/);
|
||||
|
||||
Reference in New Issue
Block a user