-
Notifications
You must be signed in to change notification settings - Fork 0
fix(gate): adversary-gate specs 邻接精化——可审计性判别(AC-14,ADR-0082/0083 关联) #481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -77,11 +77,19 @@ jobs: | |||||||||||||||
| echo "merge_group:adversary check run 已写回 success(EXPECTED_SKIP)" | ||||||||||||||||
|
|
||||||||||||||||
| - name: 预检 PR 是否含 specs/** 变更(gh + github.token) | ||||||||||||||||
| # 2026-08-31 精化(AC-14 豁免谓词确定性派生):specs/** 命中只统计 | ||||||||||||||||
| # **可审计 spec 体**——变更路径所属 specs/<dir>/ 在 PR head 上存在 | ||||||||||||||||
| # spec.md(adversary 目标契约 specs/<dir>/{spec.md,suite/,run-suite.sh} | ||||||||||||||||
| # 的判别面)。specs/ 下无 spec.md 的目录(如 test-freeze 的 MANIFEST | ||||||||||||||||
| # 派生哈希账本)是机器可校验资产而非红队审计对象——其完整性由 | ||||||||||||||||
| # 自身哈希链/签名执法,红队无面可攻。判定仍由 diff 路径集 + head 树 | ||||||||||||||||
| # 确定性派生(禁人工打标);API 失败负向断言不变(fail-closed)。 | ||||||||||||||||
| if: github.event_name == 'pull_request' | ||||||||||||||||
| id: specspr | ||||||||||||||||
| env: | ||||||||||||||||
| GH_TOKEN: ${{ github.token }} | ||||||||||||||||
| PR_API: "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}" | ||||||||||||||||
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||||||||||||||||
| run: | | ||||||||||||||||
| set -euo pipefail | ||||||||||||||||
| set +e | ||||||||||||||||
|
|
@@ -93,10 +101,60 @@ jobs: | |||||||||||||||
| echo "has_specs=true" >> "$GITHUB_OUTPUT" | ||||||||||||||||
| echo "::warning::取 PR files 失败(负向断言:视为 spec 变更)" | ||||||||||||||||
| else | ||||||||||||||||
| HASSPECS=$(echo "$FILES" | python3 -c "import json,sys;files=json.load(sys.stdin);print('true' if any(f.startswith('specs/') for f in files) else 'false')") | ||||||||||||||||
| echo "has_specs=$HASSPECS" >> "$GITHUB_OUTPUT" | ||||||||||||||||
| SPECS_HITS=$(echo "$FILES" | python3 -c "import json,sys;files=json.load(sys.stdin);print('\n'.join(f for f in files if f.startswith('specs/')))") | ||||||||||||||||
| if [[ -z "$SPECS_HITS" ]]; then | ||||||||||||||||
| echo "has_specs=false" >> "$GITHUB_OUTPUT" | ||||||||||||||||
| else | ||||||||||||||||
| # 逐变更 specs 目录核验可审计性(head 树上 specs/<dir>/spec.md 存在) | ||||||||||||||||
| AUDITABLE=0; ADJACENT_DIRS="" | ||||||||||||||||
| for d in $(echo "$SPECS_HITS" | sed 's|^specs/||' | cut -d/ -f1 | sort -u); do | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 高严重级别:保留目录名边界,避免绕过审计。
使用 JSON 结构化处理完整路径。不要通过命令替换、换行或 shell 词拆分传递目录名。调用 Contents API 时也必须对路径段进行 URL 编码;无法安全解析时应 fail-closed。 🤖 Prompt for AI Agents |
||||||||||||||||
| [[ -n "$d" ]] || continue | ||||||||||||||||
| if gh api "repos/${{ github.repository }}/contents/specs/$d/spec.md?ref=$HEAD_SHA" >/dev/null 2>&1; then | ||||||||||||||||
|
Comment on lines
+109
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 5. Whitespace paths bypass audit for d in $(...) applies shell word splitting to directory names, so a valid path such as specs/foo bar/spec.md is checked as nonexistent directories foo and bar. The workflow then labels the actual auditable directory adjacent and emits a successful skip. Agent Prompt
|
||||||||||||||||
| AUDITABLE=1 | ||||||||||||||||
| else | ||||||||||||||||
| ADJACENT_DIRS="$ADJACENT_DIRS $d" | ||||||||||||||||
|
Comment on lines
+112
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. Canonical spec bypasses audit The predicate considers only spec.md, so changes to the signed canonical body specs/IR-0003/constitution.md are classified as adjacent and receive a successful adversary check. This bypasses the repository rule requiring red-team review for spec/test-design changes. Agent Prompt
Comment on lines
+112
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. Spec deletion gets skipped Deleting or renaming away specs/<dir>/spec.md makes the head-tree lookup return missing, which classifies the contract removal as adjacent and writes a successful EXPECTED_SKIP check. A PR can therefore remove an auditable spec body without supplying a survived adversary audit. Agent Prompt
Comment on lines
+112
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4. Lookup failures fail open Every failed per-directory contents request—including rate limits, permission errors, and transient GitHub failures—is interpreted as proof that spec.md does not exist. If all lookups fail, the workflow grants a successful adjacent skip instead of preserving the stated fail-closed behavior. Agent Prompt
|
||||||||||||||||
| fi | ||||||||||||||||
| done | ||||||||||||||||
| # specs/ 根下直挂文件(无目录层)→ fail-closed 视为可审计(红队判别面外不放行) | ||||||||||||||||
| if echo "$SPECS_HITS" | grep -qv '^specs/[^/]*/'; then AUDITABLE=1; fi | ||||||||||||||||
| if [[ $AUDITABLE -eq 1 ]]; then | ||||||||||||||||
| echo "has_specs=true" >> "$GITHUB_OUTPUT" | ||||||||||||||||
| else | ||||||||||||||||
| echo "has_specs=adjacent" >> "$GITHUB_OUTPUT" | ||||||||||||||||
| echo "adjacent_dirs=$(echo $ADJACENT_DIRS)" >> "$GITHUB_OUTPUT" | ||||||||||||||||
| echo "specs 邻接变更(无可审计 spec 体):$ADJACENT_DIRS" | ||||||||||||||||
| fi | ||||||||||||||||
| fi | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| - name: specs 邻接变更(无 spec.md 审计体)——写 success check run 放行 | ||||||||||||||||
| # EXPECTED_SKIP(AC-14):specs/** 命中但全部属无 spec.md 的目录 | ||||||||||||||||
| # (MANIFEST/README 类派生资产)——确定性派生豁免,非人工打标。 | ||||||||||||||||
| if: steps.specspr.outputs.has_specs == 'adjacent' | ||||||||||||||||
| env: | ||||||||||||||||
| GH_TOKEN: ${{ github.token }} | ||||||||||||||||
| run: | | ||||||||||||||||
| set -euo pipefail | ||||||||||||||||
| SUMMARY="specs/** 邻接变更但无可审计 spec 体(${{ steps.specspr.outputs.adjacent_dirs }} 无 spec.md,adversary 目标契约不成立):EXPECTED_SKIP=True(AC-14 确定性派生豁免——哈希账本/MANIFEST 类资产由自身哈希链执法)" | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 高严重级别:将
建议修复 env:
GH_TOKEN: ${{ github.token }}
+ ADJACENT_DIRS: ${{ steps.specspr.outputs.adjacent_dirs }}
run: |
set -euo pipefail
- SUMMARY="specs/** 邻接变更但无可审计 spec 体(${{ steps.specspr.outputs.adjacent_dirs }} 无 spec.md,adversary 目标契约不成立):EXPECTED_SKIP=True(AC-14 确定性派生豁免——哈希账本/MANIFEST 类资产由自身哈希链执法)"
+ SUMMARY="specs/** 邻接变更但无可审计 spec 体(${ADJACENT_DIRS} 无 spec.md,adversary 目标契约不成立):EXPECTED_SKIP=True(AC-14 确定性派生豁免——哈希账本/MANIFEST 类资产由自身哈希链执法)"As per path instructions, 📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Path instructions |
||||||||||||||||
| python3 - "$SUMMARY" > "$RUNNER_TEMP/check_body.json" <<'PYEOF3' | ||||||||||||||||
| import json, sys, datetime as dt | ||||||||||||||||
| summary = sys.argv[1] | ||||||||||||||||
| json.dump({ | ||||||||||||||||
| "name": "adversary", | ||||||||||||||||
| "head_sha": "${{ github.event.pull_request.head.sha }}", | ||||||||||||||||
| "status": "completed", | ||||||||||||||||
| "conclusion": "success", | ||||||||||||||||
| "completed_at": dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), | ||||||||||||||||
| "output": {"title": "adversary: skipped (specs-adjacent, no auditable spec body)", "summary": summary}, | ||||||||||||||||
| }, sys.stdout) | ||||||||||||||||
| PYEOF3 | ||||||||||||||||
| curl -fsS -X POST \ | ||||||||||||||||
| -H "Authorization: Bearer $GH_TOKEN" \ | ||||||||||||||||
| -H "Accept: application/vnd.github+json" \ | ||||||||||||||||
| "https://api.github.com/repos/${{ github.repository }}/check-runs" \ | ||||||||||||||||
| -d @"$RUNNER_TEMP/check_body.json" \ | ||||||||||||||||
| && echo "specs 邻接变更:adversary check run 已写回 success(EXPECTED_SKIP)" | ||||||||||||||||
|
|
||||||||||||||||
| - name: 非 specs PR——写 success check run 并放行(github.token) | ||||||||||||||||
| if: steps.specspr.outputs.has_specs == 'false' | ||||||||||||||||
| env: | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. card: metadata line missing
📘 Rule violation§ Compliance