Skip to content
Closed
119 changes: 50 additions & 69 deletions .github/workflows/ai-review.yml
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 }}
Comment on lines +48 to +53

Copy link
Copy Markdown

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-L109

Source: Linters/SAST tools


- 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
15 changes: 7 additions & 8 deletions .github/workflows/cache-cleanup.yml
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:
Expand All @@ -13,7 +12,7 @@ permissions:

jobs:
cleanup:
name: 清理已关闭 PR 缓存
name: 清理已关闭 PR 缓存与会话
runs-on: ubuntu-latest
steps:
- name: 删除当前 PR 命名空间下的所有缓存与会话工件
Expand All @@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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/workflows

Repository: 0xTimi-labs/rust-template

Length of output: 15905


🌐 Web query:

GitHub Actions documentation concurrency cancel-in-progress workflow cancellation always() upload-artifact overwrite artifact retention

💡 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:

GitHub Actions upload-artifact overwrite true artifact deletion race behavior

💡 Result:

The overwrite: true option in GitHub Actions upload-artifact (starting from v4) is designed for sequential operations, not concurrent ones [1][2]. When enabled, the action attempts to delete any existing artifact with the same name before uploading the new one [3][4][5]. Crucially, this process is not atomic [1][2]. The implementation follows a "check-then-act" pattern: the action checks for the artifact, issues a delete command if it exists, and then initiates the upload [5]. This behavior leads to the following race conditions and limitations: 1. Parallel Execution Failure: If multiple parallel jobs attempt to upload an artifact with the same name using overwrite: true, they will frequently encounter race conditions [1][2]. For example, one job may trigger a deletion while another is in the middle of an upload, or two jobs might simultaneously attempt to delete the same artifact, causing one to fail with a conflict error (often a 409 error) [1][6][7]. 2. Non-Atomic Deletion: Because the deletion and subsequent upload are separate steps, the artifact name may be momentarily unavailable or subject to unexpected state changes if other processes are interacting with the repository's artifacts [1][2]. 3. Intended Use Case: The overwrite feature is intended for serial workflows where an artifact is updated in distinct, non-overlapping steps (e.g., uploading a file, downloading it for modification, then re-uploading it with the same name) [1][2]. For parallel jobs that produce results meant to be combined, you should use unique artifact names (e.g., incorporating matrix variables) and use the actions/upload-artifact/merge action to combine them into a single artifact after all jobs have finished [1][2][7].

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())
PY

Repository: 0xTimi-labs/rust-template

Length of output: 591


协调 PR 关闭与 AI 审查工件上传

PR 关闭事件不会取消独立的 AI Review 运行。清理任务只删除查询时存在的工件;AI Review 随后可能通过 if: always() 和 overwrite: true 重新创建 pi-session-pr-${PR_NUMBER},导致工件保留 15 天。

请在删除前取消并等待相关运行结束,并阻止已取消运行上传工件;或在 AI Review 完成事件中执行幂等清理,覆盖上传与删除之间的竞态。

4 changes: 2 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
with:
toolchain: "1.98.0"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: taiki-e/install-action@a2a5f6e99e1a31540baa0468acfa302cff0f359f # v2.86.4
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc # v2.86.7
with:
tool: cargo-llvm-cov
- run: cargo llvm-cov --workspace --all-features --locked --lcov --output-path lcov.info
Expand Down Expand Up @@ -128,7 +128,7 @@ jobs:
- run: bun install --frozen-lockfile
- run: bun run build
- name: 缓存 Playwright 浏览器内核
uses: actions/cache@3edfce9056124e459a23f683a21433670d47daca # v4.3.0
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
id: playwright-cache
with:
path: ~/.cache/ms-playwright
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
with:
toolchain: "1.98.0"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: taiki-e/install-action@a2a5f6e99e1a31540baa0468acfa302cff0f359f # v2.86.4
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc # v2.86.7
with:
tool: cargo-mutants
- run: cargo mutants --all-features --in-place
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
Expand Down Expand Up @@ -128,7 +128,7 @@ jobs:
- name: enable windows longpaths
run: |
git config --global core.longpaths true
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
Expand Down Expand Up @@ -193,7 +193,7 @@ jobs:
DIST_TAG: ${{ needs.plan.outputs.tag }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
Expand Down Expand Up @@ -250,7 +250,7 @@ jobs:
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
Expand Down Expand Up @@ -320,7 +320,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
28 changes: 13 additions & 15 deletions .github/workflows/review-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

两条评论共用同一个 marker,部分失败后无法补发。

第 151 行和第 157 行使用相同的 MARKER。第 142 行只要发现任意一条带 marker 的评论就整体跳过。

如果 @coderabbitai 评论创建成功而 @greptileai 评论失败(限流、网络错误),重跑该工作流会在第 142 行命中第一条评论并直接返回。@greptileai review 命令将永久缺失。

请为每个审查工具使用独立 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 行的 MARKER 常量。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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`,
});
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}`,
});
}

2 changes: 1 addition & 1 deletion .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: taiki-e/install-action@6cd13508893c0e7eab5f273c2575d3859bd7229a # v2.85.12
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc # v2.86.7
with:
tool: cargo-deny
- name: 检查依赖合规与安全漏洞
Expand Down
Loading
Loading