-
Notifications
You must be signed in to change notification settings - Fork 0
feat(ci): 完善门禁签名去重、Fork隔离与依赖版本升级 #9
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
6343222
b400459
a419e4e
6d9dd26
016431b
262ce5b
cfc6968
11224d8
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 |
|---|---|---|
| @@ -1,111 +1,92 @@ | ||
| name: AI Review | ||
|
|
||
| # 自建 AI 审查流水线(pi 方案),当前默认跳过。 | ||
| # | ||
| # 启用步骤—— | ||
| # 1. 专用账号登录 pi,导出 ~/.pi/agent/auth.json 内容到仓库 secret `PI_AUTH_JSON` | ||
| # (必须专用账号:Codex 等 OAuth provider 的 refresh token 会轮换,与本地共用会互相顶掉) | ||
| # 2. 仓库 Settings → Secrets and variables → Actions → Variables 新建 | ||
| # AI_REVIEW_ENABLED = true | ||
| # | ||
| # 触发方式:手动(workflow_dispatch),输入 PR 编号。 | ||
| # 如需"CI 全绿才审查"的硬门禁,把本 workflow 改为 workflow_run 监听 CI 完成, | ||
| # 或在分支保护中将本 check 设为 required。 | ||
|
|
||
| on: | ||
| issue_comment: | ||
| types: [created] | ||
| workflow_dispatch: | ||
| inputs: | ||
| pr_number: | ||
| description: "要审查的 PR 编号" | ||
| description: "Pull Request Number" | ||
| required: true | ||
| type: number | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| type: string | ||
|
|
||
| concurrency: | ||
| group: ai-review-${{ inputs.pr_number }} | ||
| cancel-in-progress: false | ||
| group: ai-review-${{ github.event.issue.number || inputs.pr_number }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| review: | ||
| name: Pi Review | ||
| name: Timi Reviewer | ||
| runs-on: ubuntu-latest | ||
| # 双重限制:变量开关 + 仅内部成员 PR(fork PR 的代码不可信,禁止接触凭据) | ||
| if: >- | ||
| vars.AI_REVIEW_ENABLED == 'true' && | ||
| github.event.pull_request.head.repo.fork != true | ||
| timeout-minutes: 30 | ||
| ( | ||
| github.event_name == 'workflow_dispatch' || | ||
| ( | ||
| github.event.issue.pull_request != null && | ||
| contains(github.event.comment.body, '@timi-ai') && | ||
| (github.event.comment.author_association == 'OWNER' || | ||
| github.event.comment.author_association == 'MEMBER' || | ||
| github.event.comment.author_association == 'COLLABORATOR') | ||
| ) | ||
| ) | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| steps: | ||
| # ⚠️ 安全模型:本 job 会检出被审 PR 的 head 并在其目录内执行 agent。 | ||
| # 恶意 PR 可通过 .pi/ 配置、扩展或提示注入尝试接管 agent。 | ||
| # 缓解措施:凭据写入晚于依赖安装;agent 提示词来自可信的 main 分支; | ||
| # 仅对内部成员 PR 启用。启用前请阅读 pi 官方安全文档评估风险。 | ||
|
|
||
| # 显式检出被审 PR 的 head,不依赖 agent 隐式取 diff | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| - name: 检出代码 | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| ref: refs/pull/${{ github.event.inputs.pr_number }}/head | ||
| ref: refs/pull/${{ github.event.issue.number || inputs.pr_number }}/head | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | ||
| - name: 恢复受信任的审查资源 | ||
| run: git checkout origin/main -- scripts/ai-review.ts REVIEW_GUIDELINES.md 2>/dev/null || true | ||
|
|
||
| - name: 获取 Timi AI Bot 凭据 | ||
| id: bot-token | ||
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | ||
| with: | ||
| app-id: ${{ secrets.TIMI_AI_APP_ID }} | ||
| private-key: ${{ secrets.TIMI_AI_PRIVATE_KEY }} | ||
|
|
||
| - name: 安装 Bun 运行时 | ||
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | ||
| with: | ||
| bun-version: "1.3.14" | ||
| # 安装依赖必须先于凭据落盘:浮动依赖的安装代码不可接触 PI_AUTH_JSON; | ||
| # PI_CODING_AGENT_DIR 与运行时步骤保持一致,保证扩展装到 agent 实际读取的目录 | ||
| - name: 安装 pi 与 review 扩展(跟随最新版) | ||
|
|
||
| - name: 安装依赖 | ||
| env: | ||
| PI_CODING_AGENT_DIR: ${{ runner.temp }}/pi-agent | ||
| run: | | ||
| bun install -g @earendil-works/pi-coding-agent | ||
| pi install git:github.com/earendil-works/pi-review | ||
|
|
||
| - name: 写入 pi 认证 | ||
| - name: 写入认证 | ||
| env: | ||
| PI_AUTH_JSON: ${{ secrets.PI_AUTH_JSON }} # 经环境变量传递,避免内插进 shell | ||
| PI_AUTH_JSON: ${{ secrets.PI_AUTH_JSON }} | ||
| run: | | ||
| mkdir -p "$RUNNER_TEMP/pi-agent" | ||
| printf '%s' "$PI_AUTH_JSON" > "$RUNNER_TEMP/pi-agent/auth.json" | ||
| chmod 600 "$RUNNER_TEMP/pi-agent/auth.json" | ||
|
|
||
| - name: 恢复历史 Review 会话 | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| PR_NUMBER: ${{ github.event.inputs.pr_number }} | ||
| run: | | ||
| mkdir -p "$RUNNER_TEMP/pi" | ||
| ARTIFACT_ID=$(gh api "repos/${{ github.repository }}/actions/artifacts?name=pi-session-pr-${PR_NUMBER}" --jq '.artifacts[0].id // empty') | ||
| if [ -n "$ARTIFACT_ID" ]; then | ||
| gh api "repos/${{ github.repository }}/actions/artifacts/${ARTIFACT_ID}/zip" > "$RUNNER_TEMP/session.zip" | ||
| unzip -q -o "$RUNNER_TEMP/session.zip" -d "$RUNNER_TEMP/pi/" | ||
| fi | ||
|
|
||
| - name: 运行审查 | ||
| shell: bash | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| PR_NUMBER: ${{ github.event.inputs.pr_number }} # 经环境变量传入,避免内插进 shell | ||
| PI_CODING_AGENT_DIR: ${{ runner.temp }}/pi-agent | ||
| run: | | ||
| set -o pipefail | ||
| # 审查规范取自可信的 main 分支,而非被审 PR 的 head,防指令注入 | ||
| git show origin/main:REVIEW_GUIDELINES.md > "$RUNNER_TEMP/guidelines.md" | ||
| pi -p --approve --session "$RUNNER_TEMP/pi/session.jsonl" "审查 PR #${PR_NUMBER}, | ||
| 按以下规范输出分级 findings 和 verdict。不要修改任何代码。 | ||
| 规范内容:$(cat "$RUNNER_TEMP/guidelines.md")" | tee review-output.md | ||
| BOT_TOKEN: ${{ steps.bot-token.outputs.token }} | ||
| GH_REPO: ${{ github.repository }} | ||
| PR_NUMBER: ${{ github.event.issue.number || inputs.pr_number }} | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| COMMENT_BODY: ${{ github.event.comment.body }} | ||
| RUNNER_TEMP: ${{ runner.temp }} | ||
| run: bun run scripts/ai-review.ts | ||
|
|
||
| - name: 保存审查会话 | ||
| - name: 保存会话工件 | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| if: always() | ||
| with: | ||
| name: pi-session-pr-${{ github.event.inputs.pr_number }} | ||
| path: ${{ runner.temp }}/pi/session.jsonl | ||
| name: pi-session-pr-${{ github.event.issue.number || inputs.pr_number }} | ||
| path: ${{ runner.temp }}/pi-session/ | ||
| retention-days: 15 | ||
| overwrite: true | ||
|
|
||
| - name: 发布审查意见 | ||
| env: | ||
| PR_NUMBER: ${{ github.event.inputs.pr_number }} | ||
| run: gh pr comment "$PR_NUMBER" --body-file review-output.md | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,6 @@ | ||
| name: Cache Cleanup | ||
|
|
||
| # PR 缓存生命周期管理:当 PR 合并或关闭时,自动清除该 PR 独占的分支缓存, | ||
| # 确保仓库仅维护 main 分支的有效基线缓存,防止 10GB 存储池因历史 PR 堆积膨胀。 | ||
| # PR 生命周期管理:当 PR 合并或关闭时,自动清除该 PR 独占的分支编译缓存与 AI 审查会话工件。 | ||
|
|
||
| on: | ||
| pull_request: | ||
|
|
@@ -13,7 +12,7 @@ permissions: | |
|
|
||
| jobs: | ||
| cleanup: | ||
| name: 清理已关闭 PR 缓存 | ||
| name: 清理已关闭 PR 缓存与会话 | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: 删除当前 PR 命名空间下的所有缓存与会话工件 | ||
|
|
@@ -22,9 +21,9 @@ jobs: | |
| GH_REPO: ${{ github.repository }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| run: | | ||
| # 1. 删除当前 PR 的分支独占缓存 | ||
| gh cache list --ref "refs/pull/${PR_NUMBER}/merge" --limit 100 --json id --jq '.[].id' | xargs -r -n 1 gh cache delete | ||
| # 2. 物理销毁当前 PR 的所有历史 AI 审查会话工件 | ||
| # 1. 删除当前 PR 的分支独占编译缓存 | ||
| gh cache delete --all --ref "refs/pull/${PR_NUMBER}/merge" 2>/dev/null || true | ||
| # 2. 物理销毁当前 PR 的 AI 审查会话工件 | ||
| gh api --paginate "repos/${GH_REPO}/actions/artifacts" \ | ||
| --jq ".artifacts[] | select(.name | startswith(\"pi-session-pr-${PR_NUMBER}\")) | .id" \ | ||
| | xargs -r -n 1 gh api --method DELETE "repos/${GH_REPO}/actions/artifacts/{}" | ||
| --jq ".artifacts[] | select(.name == \"pi-session-pr-${PR_NUMBER}\") | .id" \ | ||
| | xargs -r -I{} gh api --method DELETE "repos/${GH_REPO}/actions/artifacts/{}" | ||
|
Comment on lines
+26
to
+29
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. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/*'
printf '%s\n' '--- cache-cleanup.yml ---'
cat -n .github/workflows/cache-cleanup.yml
printf '%s\n' '--- ai-review.yml relevant sections ---'
cat -n .github/workflows/ai-review.yml | sed -n '1,125p'
printf '%s\n' '--- references to session artifact and cleanup ---'
rg -n -C 3 'pi-session-pr-|cache-cleanup|workflow_run|pull_request|actions/artifacts|always\(\)' .github/workflowsRepository: 0xTimi-labs/rust-template Length of output: 15905 🌐 Web query:
💡 Result: In GitHub Actions, concurrency control, artifact management, and job execution behavior work as follows: Concurrency and Cancel-in-Progress The concurrency keyword limits how many workflow runs or jobs within the same concurrency group execute at once [1][2]. By default, a concurrency group allows at most one running job/workflow and one pending job/workflow [3][4]. If a new job is queued while another is pending, the existing pending job is cancelled and replaced by the new one [1][3]. Setting cancel-in-progress: true will also cancel any currently running job in that concurrency group [1][3]. You can also use conditional expressions with cancel-in-progress to dynamically control this behavior based on the branch or other context [3][4]. Note that cancel-in-progress cannot be used with the queue: max option [1][3]. Artifact Upload and Overwrite In version 4 and later of the upload-artifact action, artifacts are immutable by default [5][6][7]. If you attempt to upload an artifact with a name that already exists in the same workflow run, the action will fail [7]. To effectively "overwrite" an artifact, you must set overwrite: true in the upload-artifact action; this deletes the existing artifact before the new one is uploaded [8][9]. Note that this assigns the new artifact a different ID [5][6]. Artifact Retention By default, artifacts are retained for 90 days [10][11]. This period can be customized at the organization or repository level, ranging from 1 to 90 days for public repositories, or up to 400 days for private repositories [10]. You can also set a custom retention period for an individual artifact using the retention-days parameter within the upload-artifact action [12][11]. This custom value cannot exceed the maximum retention limit configured for the repository or organization [12]. Always Function The always expression is a function used in job-level or step-level if conditionals [1]. It ensures that a job or step runs even if previous steps have failed, were canceled, or were skipped [1]. This is commonly used for cleanup steps or reporting, such as uploading logs or artifacts even after a test failure. Top Results: [1], [3], [8], [7], [10], [12] Citations:
🌐 Web query:
💡 Result: The Citations:
🏁 Script executed: #!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
import re
cleanup = Path(".github/workflows/cache-cleanup.yml").read_text()
review = Path(".github/workflows/ai-review.yml").read_text()
print("cleanup trigger:", re.search(r"on:\s*\n\s*pull_request:\s*\n\s*types:\s*\[([^\]]+)\]", cleanup).group(1))
print("review triggers:", re.search(r"on:\s*\n((?:\s{2,}.*\n)+?)\nconcurrency:", review).group(1).strip())
print("cleanup concurrency:", "present" if re.search(r"^concurrency:", cleanup, re.M) else "absent")
print("review concurrency group:",
re.search(r"group:\s*(.+)", review).group(1).strip())
print("review cancellation:",
re.search(r"cancel-in-progress:\s*(.+)", review).group(1).strip())
print("upload condition:",
re.search(r"^\s*if:\s*(.+)", review[review.index("uses: actions/upload-artifact"):], re.M).group(1).strip())
print("upload overwrite:",
re.search(r"^\s*overwrite:\s*(.+)", review[review.index("uses: actions/upload-artifact"):], re.M).group(1).strip())
print("upload retention:",
re.search(r"^\s*retention-days:\s*(.+)", review[review.index("uses: actions/upload-artifact"):], re.M).group(1).strip())
PYRepository: 0xTimi-labs/rust-template Length of output: 591 协调 PR 关闭与 AI 审查工件上传 PR 关闭事件不会取消独立的 AI Review 运行。清理任务只删除查询时存在的工件;AI Review 随后可能通过 请在删除前取消并等待相关运行结束,并阻止已取消运行上传工件;或在 AI Review 完成事件中执行幂等清理,覆盖上传与删除之间的竞态。 |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -101,15 +101,23 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| group: review-gate-pr-${{ needs.resolve.outputs.number }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cancel-in-progress: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: 获取 Timi AI Bot 凭据 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: bot-token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app-id: ${{ secrets.TIMI_AI_APP_ID }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private-key: ${{ secrets.TIMI_AI_PRIVATE_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: 发布首次审查命令评论 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PR_NUMBER: ${{ needs.resolve.outputs.number }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| github-token: ${{ github.token }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| github-token: ${{ steps.bot-token.outputs.token }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { owner, repo } = context.repo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const issueNumber = Number(process.env.PR_NUMBER); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const MARKER = '<!-- review-gate: initial-trigger -->'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentPullRequest = await github.rest.pulls.get({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -131,30 +139,20 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: issueNumber, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| per_page: 100, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const automaticCommands = new Set([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '@coderabbitai review', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '@greptileai review', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hasAutomaticCommand = comments.some( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (comment) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment.user?.login === 'github-actions[bot]' && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| automaticCommands.has(comment.body), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hasAutomaticCommand) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| core.info('跳过:PR 已执行过首次自动审查触发。'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (comments.some((c) => c.body?.includes(MARKER))) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| core.info('跳过:已存在自动审查命令评论。'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await github.rest.issues.createComment({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: issueNumber, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: '@coderabbitai review', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: `${MARKER}\n@coderabbitai review`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await github.rest.issues.createComment({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: issueNumber, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: '@greptileai review', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: `${MARKER}\n@greptileai review`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+142
to
158
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. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 两条评论共用同一个 marker,部分失败后无法补发。 第 151 行和第 157 行使用相同的 如果 请为每个审查工具使用独立 marker,并分别判断。 🐛 建议修复:按工具分别去重- if (comments.some((c) => c.body?.includes(MARKER))) {
- core.info('跳过:已存在自动审查命令评论。');
- return;
- }
-
- await github.rest.issues.createComment({
- owner,
- repo,
- issue_number: issueNumber,
- body: `${MARKER}\n@coderabbitai review`,
- });
- await github.rest.issues.createComment({
- owner,
- repo,
- issue_number: issueNumber,
- body: `${MARKER}\n@greptileai review`,
- });
+ const targets = [
+ { id: 'coderabbit', command: '`@coderabbitai` review' },
+ { id: 'greptile', command: '`@greptileai` review' },
+ ];
+ for (const target of targets) {
+ const marker = `<!-- review-gate: initial-trigger:${target.id} -->`;
+ if (comments.some((c) => c.body?.includes(marker))) {
+ core.info(`跳过:已存在 ${target.id} 审查命令评论。`);
+ continue;
+ }
+ await github.rest.issues.createComment({
+ owner,
+ repo,
+ issue_number: issueNumber,
+ body: `${marker}\n${target.command}`,
+ });
+ }同时删除第 120 行的 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
两个工作流签发的 App token 都未限定范围。
actions/create-github-app-token在缺省配置下签发覆盖该 App 全部安装权限、全部可访问仓库的 token。请在两处都显式声明owner、repositories和permission-*,按最小权限收窄。.github/workflows/ai-review.yml#L48-L53:添加owner、repositories,并限定为permission-issues: write与permission-actions: read(restoreSessionArtifact需要读取工件)。该 token 通过BOT_TOKEN传给scripts/ai-review.ts执行gh api,暴露面最大。.github/workflows/review-gate.yml#L104-L109:添加owner、repositories,并限定为permission-pull-requests: read与permission-issues: write。🧰 Tools
🪛 zizmor (1.29.0)
[error] 50-50: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
📍 Affects 2 files
.github/workflows/ai-review.yml#L48-L53(this comment).github/workflows/review-gate.yml#L104-L109Source: Linters/SAST tools