diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 967b116..0c34018 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,13 +16,20 @@ concurrency: jobs: actionlint: name: Workflow lint (actionlint + YAML) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - name: Install actionlint + - name: Install actionlint v1.7.12 + env: + ACTIONLINT_VERSION: 1.7.12 run: | - bash <(curl -sSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) - sudo mv actionlint /usr/local/bin/ + curl --fail --location --silent --show-error \ + "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \ + --output actionlint.tar.gz + echo "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 actionlint.tar.gz" \ + | sha256sum --check --strict - + tar -xzf actionlint.tar.gz actionlint + sudo install -m 0755 actionlint /usr/local/bin/actionlint - name: Lint all workflow files run: actionlint -color .github/workflows/*.yml - name: Validate YAML parses diff --git a/.github/workflows/python-quality-baseline.yml b/.github/workflows/python-quality-baseline.yml index 8f38d55..2ba7e65 100644 --- a/.github/workflows/python-quality-baseline.yml +++ b/.github/workflows/python-quality-baseline.yml @@ -13,7 +13,7 @@ # # jobs: # quality-baseline: -# uses: ReSerendipity/.github/.github/workflows/python-quality-baseline.yml@main +# uses: ReSerendipity/.github/.github/workflows/python-quality-baseline.yml@ # with: # package: app/integrated_app # coverage_min: 65 @@ -23,6 +23,8 @@ # permissions: # contents: read # +# 可复用工作流调用方应锁定已审阅的提交 SHA,不使用会漂移的 @main。 +# # ⚠️ 维护约定(证据绑定): # - 修改本文件等于同时修改四个仓库的门禁行为,合并前须在至少一个 # 试点仓跑绿; @@ -114,10 +116,10 @@ jobs: timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Set up Python ${{ inputs.python_version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: ${{ inputs.python_version }} cache: 'pip' @@ -155,10 +157,10 @@ jobs: timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Set up Python ${{ inputs.python_version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: ${{ inputs.python_version }} cache: 'pip' @@ -173,9 +175,18 @@ jobs: - name: Run mypy and enforce ratchet run: | - mypy ${{ inputs.mypy_target }} --ignore-missing-imports --no-error-summary > mypy.log 2>&1 || true + if mypy ${{ inputs.mypy_target }} --ignore-missing-imports --no-error-summary > mypy.log 2>&1; then + MYPY_STATUS=0 + else + MYPY_STATUS=$? + fi COUNT=$(grep -c 'error:' mypy.log || true) COUNT=${COUNT:-0} + if [ "$MYPY_STATUS" -gt 1 ] || { [ "$MYPY_STATUS" -eq 1 ] && [ "$COUNT" -eq 0 ]; }; then + echo "::error::mypy 执行失败 (exit $MYPY_STATUS),拒绝将工具/运行时失败误计为零错误" + head -n 60 mypy.log + exit 1 + fi if [ -f '${{ inputs.mypy_baseline_file }}' ]; then BASELINE=$(tr -d '[:space:]' < '${{ inputs.mypy_baseline_file }}') else diff --git a/.github/workflows/self-purify.yml b/.github/workflows/self-purify.yml index 76f0193..6d6ead9 100644 --- a/.github/workflows/self-purify.yml +++ b/.github/workflows/self-purify.yml @@ -9,25 +9,52 @@ name: Family Self-Purify Check # ③ README 未引用 org 级仓库(组织级健康文档链接缺失) # 说明:AGENTS.md 为本地独享文件(gitignored),CI 拉取的检出中不存在, # 故其行数上限无法在此检查,由 AI 会话自检 + 本地钩子约束。 +# 默认保留家族非阻塞语义。调用方审计并准备好阻断本地治理文档后,可传 +# enforce_critical_checks: true;只有该核心规则会进入独立阻断 job。 on: workflow_call: + inputs: + enforce_critical_checks: + description: 是否将本地治理文档不得被跟踪设为阻断门禁(默认关闭以兼容现有仓库) + required: false + type: boolean + default: false permissions: contents: read jobs: + critical-governance: + if: inputs.enforce_critical_checks + name: 自净化核心规则(阻断) + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + + - name: 本地治理文档不得被 git 跟踪 + run: | + HITS=$(git ls-files | grep -E '^(docs/(plans|project|_devarchive|agents|execution)/|LOCAL_RULES\.md$|FIX_LOG\.md$)' \ + | grep -vE '^(docs/reports/(落地执行总结|执行对照表)-桌面分发与安全加固-20260910\.md|docs/execution/(RELEASE_VERIFICATION\.md|(执行对照表|落地执行总结)-桌面分发与安全加固-20260910\.md|依赖与安全跟踪机制-20260911\.md)|docs/project/(KNOWN_GOTCHAS\.md|AI_DEV_SOPS\.md))$' || true) + if [ -n "$HITS" ]; then + echo "::error::以下本地治理文档被 git 跟踪(应 git rm --cached 且由 .gitignore 覆盖):" + echo "$HITS" + exit 1 + fi + echo "OK:无本地治理文档被跟踪" + self-purify: name: 自净化检查 - # 家族绿线约定:非阻塞在此实现(调用方 uses job 不允许 continue-on-error)。 - # 任一检查失败会红该 step 并输出 ::error 注解,但 job/run 结论仍为 success。 + # 保留现有家族兼容语义:其余健康检查继续告警但不阻断调用仓库。 continue-on-error: true runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: ① 本地治理文档不得被 git 跟踪 + if: ${{ !inputs.enforce_critical_checks }} run: | HITS=$(git ls-files | grep -E '^(docs/(plans|project|_devarchive|agents|execution)/|LOCAL_RULES\.md$|FIX_LOG\.md$)' \ | grep -vE '^(docs/reports/(落地执行总结|执行对照表)-桌面分发与安全加固-20260910\.md|docs/execution/(RELEASE_VERIFICATION\.md|(执行对照表|落地执行总结)-桌面分发与安全加固-20260910\.md|依赖与安全跟踪机制-20260911\.md)|docs/project/(KNOWN_GOTCHAS\.md|AI_DEV_SOPS\.md))$' || true) diff --git a/README.md b/README.md index b750b3a..636a63b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,10 @@ 治理约定细节见 `REPOSITORY_GUIDELINES.md`(命名/分支/密钥备份规范)、`CONTRIBUTING.md`、`CODE_OF_CONDUCT.md`、`SECURITY.md`、`SUPPORT.md`。 +## 复用工作流 + +`.github/workflows/` 中的家族复用工作流由各仓通过 `workflow_call` 接入。调用方应引用已审阅的提交 SHA,而不是会漂移的 `@main`。`self-purify.yml` 默认维持非阻断兼容模式;调用仓完成规则核查后,可设置 `enforce_critical_checks: true`,将“本地治理文档不得被 git 跟踪”作为独立阻断门禁,其余健康检查仍保持告警性质。 + ## 维护原则 - 默认文件保持通用,不写入某个项目独有的运行步骤或模型说明。