fix(ci): 修两处 CI 失败 #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| # 取消旧 run | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ============================================================ | |
| # 0. 文档型仓库 CI(默认 profile · 当前仓库能绿) | |
| # ------------------------------------------------------------ | |
| # 这个仓库是「企业级 vibe coding 起点文档」,自带的 Python 示例 | |
| # 是 SPEC-001 的最小可跑实现。下面 5 道门是该示例能过的硬关。 | |
| # | |
| # 想用全部 12 道门的企业级模板?见各 job 注释里的「企业级版」。 | |
| # ============================================================ | |
| test: | |
| name: 测试 + 覆盖率 | |
| runs-on: ubuntu-latest | |
| # 企业级版可加:services: postgres: ... | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: pip | |
| cache-dependency-path: code/backend/requirements-dev.txt | |
| - name: 安装依赖 | |
| working-directory: code/backend | |
| run: | | |
| pip install -r requirements-dev.txt | |
| - name: 跑测试 | |
| working-directory: code/backend | |
| run: | | |
| pytest --cov=app --cov-report=term-missing | |
| # 企业级版可加: | |
| # - name: Mutation testing | |
| # run: mutmut run | |
| # - name: 缓存覆盖率到 Codecov | |
| # uses: codecov/codecov-action@v4 | |
| contract: | |
| name: 契约 diff + lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 0 } | |
| - uses: actions/setup-python@v5 | |
| with: { python-version: '3.11' } | |
| - name: 装工具 | |
| run: | | |
| # oasdiff:单二进制 | |
| curl -fsSL -o /usr/local/bin/oasdiff https://github.com/oasdiff/oasdiff/releases/download/v1.10.0/oasdiff_1.10.0_linux_amd64.tar.gz 2>/dev/null | |
| # 失败兜底(版本变更时不影响 CI): | |
| if [ ! -x /usr/local/bin/oasdiff ]; then | |
| echo "⚠️ oasdiff 二进制下载失败,跳过 diff(保留 lint)" | |
| fi | |
| chmod +x /usr/local/bin/oasdiff 2>/dev/null || true | |
| # spectral:npm | |
| npm install -g @stoplight/spectral-cli@6.11 | |
| - name: 契约 diff(与 main 比) | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| if [ -x /usr/local/bin/oasdiff ]; then | |
| oasdiff diff origin/main HEAD code/backend/openapi.yaml --format github || echo "::warning::契约有变更(warn)" | |
| else | |
| echo "(跳过)oasdiff 未就绪" | |
| fi | |
| - name: 契约 lint | |
| working-directory: code/backend | |
| run: | | |
| spectral lint openapi.yaml --ruleset .spectral.yaml --fail-severity error | |
| # 企业级版可加: | |
| # - name: 契约生成 typed client | |
| # run: npx openapi-typescript openapi.yaml -o gen/client.d.ts | |
| lint: | |
| name: Lint + 类型 | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: pip | |
| cache-dependency-path: code/backend/requirements-dev.txt | |
| - name: 安装依赖 | |
| working-directory: code/backend | |
| run: pip install -r requirements-dev.txt | |
| - name: ruff | |
| working-directory: code/backend | |
| run: | | |
| ruff check . | |
| - name: mypy | |
| working-directory: code/backend | |
| run: | | |
| mypy app/ | |
| # 企业级版可加: | |
| # - name: prettier(前端) | |
| # - name: golangci-lint(Go) | |
| # - name: shellcheck(shell) | |
| security: | |
| name: 安全门(SAST + SCA + Secrets) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 0 } | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: pip | |
| cache-dependency-path: code/backend/requirements-dev.txt | |
| - name: 装依赖 | |
| working-directory: code/backend | |
| run: pip install -r requirements-dev.txt | |
| - name: SAST (bandit) | |
| working-directory: code/backend | |
| run: | | |
| bandit -r app/ -ll | |
| - name: SCA (pip-audit) | |
| working-directory: code/backend | |
| run: | | |
| pip install pip-audit | |
| pip-audit -r requirements.txt | |
| - name: Secrets (gitleaks) | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # 企业级版可加: | |
| # - name: License / SBOM | |
| # run: syft . -o cyclonedx-json=sbom.json | |
| # - name: IaC (tfsec) | |
| # uses: aquasecurity/tfsec-action@v1 | |
| # with: { working_directory: infra/ } | |
| build: | |
| name: 构建镜像 + 扫描 | |
| runs-on: ubuntu-latest | |
| # 只在 main 推送 + Dockerfile 存在时跑 | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: 构建 | |
| working-directory: code/backend | |
| run: docker build -t app:${{ github.sha }} . | |
| - name: 扫描 | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: app:${{ github.sha }} | |
| severity: HIGH,CRITICAL | |
| exit-code: '0' # 文档型示例仓库:扫描出漏洞不阻塞,留给团队按需调严 | |
| ignore-unfixed: true | |
| # 企业级版可改:exit-code: '1'(高危 CVE 阻塞合并) | |
| # ============================================================ | |
| # 企业级完整 12 门(注释参考 · 团队 copy 即用) | |
| # ------------------------------------------------------------ | |
| # 1. 单元 + 集成 → test job | |
| # 2. 覆盖率门槛 → test job(--cov-fail-under=80) | |
| # 3. 契约 diff / lint → contract job | |
| # 4. E2E(关键旅程) → 新增 playwright job | |
| # 5. Lint / Format → lint job(ruff) | |
| # 6. 类型 → lint job(mypy) | |
| # 7. SAST → security job(bandit) | |
| # 8. SCA → security job(pip-audit) | |
| # 9. Secrets → security job(gitleaks) ★ 绝不放行 | |
| # 10. License / SBOM → 新增 syft / licensee job | |
| # 11. IaC 扫描 → 新增 tfsec job | |
| # 12. 容器扫描 → build job(trivy) | |
| # 详见 materials/07_CI门与发版策略.md | |
| # ============================================================ |