Skip to content

Testcibom#2810

Closed
Chiloven945 wants to merge 2 commits into
PCL-Community:devfrom
Likos-Lupus:testcibom
Closed

Testcibom#2810
Chiloven945 wants to merge 2 commits into
PCL-Community:devfrom
Likos-Lupus:testcibom

Conversation

@Chiloven945
Copy link
Copy Markdown
Contributor

@Chiloven945 Chiloven945 commented May 9, 2026

Summary by Sourcery

CI:

  • 引入一个 GitHub Actions 工作流程,用于扫描拉取请求中变更的文件是否包含 BOM,一旦发现就会在该拉取请求上发表评论。
Original summary in English

Summary by Sourcery

CI:

  • Introduce a GitHub Actions workflow that scans changed PR files for BOMs and comments on the pull request when any are found.

@pcl-ce-automation pcl-ce-automation Bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: L PR 大小评估:大型 labels May 9, 2026
@Chiloven945 Chiloven945 closed this May 9, 2026
@pcl-ce-automation pcl-ce-automation Bot removed 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: L PR 大小评估:大型 labels May 9, 2026
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 9, 2026

审查者指南

添加一个 GitHub Actions 工作流程,用于检查拉取请求中所有变更文件是否包含 Unicode 字节顺序标记(BOM)。一旦检测到 BOM,该流程会在 PR 上发表评论提供详情,并将工作流程标记为失败。

BOM 检测与 PR 评论更新的时序图

sequenceDiagram
  actor Dev
  participant PR as PullRequest
  participant GH as GitHub
  participant WF as Workflow_check-bom
  participant JS as BOM_check_script
  participant API as GitHub_REST_API

  Dev->>GH: Open or update PR
  GH-->>WF: Trigger pull_request_target event
  WF->>WF: Run job check-bom
  WF->>JS: Execute github-script step

  JS->>API: pulls.listFiles(owner, repo, pull_number)
  API-->>JS: Changed files list

  loop For each non-removed file
    JS->>JS: Read first 4 bytes from file
    JS->>JS: detectBom(buffer)
    JS->>JS: Accumulate files with BOM
  end

  alt No files with BOM
    JS-->>WF: Log "No BOM found"
    WF-->>GH: Job succeeds
  else Files with BOM found
    JS->>API: issues.listComments(owner, repo, issue_number)
    API-->>JS: Existing comments
    alt Existing marker comment found
      JS->>API: issues.updateComment(owner, repo, comment_id, body)
    else No marker comment
      JS->>API: issues.createComment(owner, repo, issue_number, body)
    end
    JS-->>WF: core.setFailed("BOM found...")
    WF-->>GH: Job fails
    GH-->>PR: Updated bot comment with BOM details
  end
Loading

文件级变更

变更 详情 文件
引入一个 GitHub Actions 工作流程,用于扫描 PR 中变更的文件是否存在 Unicode BOM,并将任何发现反馈到拉取请求中。
  • 在 pull_request_target 事件(opened、synchronize、reopened、ready_for_review)上触发工作流程,对 contents 拥有只读权限,对 pull requests 和 issues 拥有写权限。
  • 使用 actions/checkout,基于 PR 的 head 仓库和 SHA 检出拉取请求的 head 提交,不持久化凭据。
  • 使用 actions/github-script 分页获取 PR 中变更文件列表,跳过已删除文件,并从工作区中读取每个现存文件的前几个字节。
  • 实现一个 BOM 检测器,在每个文件开头检查 UTF-32 BE/LE、UTF-8 以及 UTF-16 BE/LE 的 BOM 序列。
  • 收集包含 BOM 的文件,如果发现任何文件,则用中文在 PR 上构建或更新一个机器人评论,列出所有问题文件,并附带一个隐藏标记以实现幂等更新,然后通过 core.setFailed 将任务标记为失败。
.github/workflows/bom-check.yml
test.txt

提示与命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub Issue: 通过回复审查评论,要求 Sourcery 从该评论创建一个 issue。你也可以回复审查评论,写上 @sourcery-ai issue 来从该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题中任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中的任意位置写上 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时(重新)生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。适用于你已经处理完所有评论且不想再看到它们的情况。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。特别适合想要从头开始新的审查时使用——别忘了再评论 @sourcery-ai review 来触发新的审查!

自定义你的体验

访问你的 控制面板 以:

  • 启用或禁用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

Adds a GitHub Actions workflow that checks all changed files in pull requests for the presence of Unicode byte order marks (BOMs) and comments on the PR with details when any are detected, failing the workflow in that case.

Sequence diagram for BOM detection and PR comment update

sequenceDiagram
  actor Dev
  participant PR as PullRequest
  participant GH as GitHub
  participant WF as Workflow_check-bom
  participant JS as BOM_check_script
  participant API as GitHub_REST_API

  Dev->>GH: Open or update PR
  GH-->>WF: Trigger pull_request_target event
  WF->>WF: Run job check-bom
  WF->>JS: Execute github-script step

  JS->>API: pulls.listFiles(owner, repo, pull_number)
  API-->>JS: Changed files list

  loop For each non-removed file
    JS->>JS: Read first 4 bytes from file
    JS->>JS: detectBom(buffer)
    JS->>JS: Accumulate files with BOM
  end

  alt No files with BOM
    JS-->>WF: Log "No BOM found"
    WF-->>GH: Job succeeds
  else Files with BOM found
    JS->>API: issues.listComments(owner, repo, issue_number)
    API-->>JS: Existing comments
    alt Existing marker comment found
      JS->>API: issues.updateComment(owner, repo, comment_id, body)
    else No marker comment
      JS->>API: issues.createComment(owner, repo, issue_number, body)
    end
    JS-->>WF: core.setFailed("BOM found...")
    WF-->>GH: Job fails
    GH-->>PR: Updated bot comment with BOM details
  end
Loading

File-Level Changes

Change Details Files
Introduce a GitHub Actions workflow that scans PR-changed files for Unicode BOMs and reports any findings back to the pull request.
  • Trigger the workflow on pull_request_target events (opened, synchronize, reopened, ready_for_review) with read access to contents and write access to pull requests and issues.
  • Check out the head commit of the pull request using actions/checkout with the PR head repo and SHA, without persisting credentials.
  • Use actions/github-script to paginate the list of changed files in the PR, skip removed files, and read the first few bytes of each existing file from the workspace.
  • Implement a BOM detector that checks for UTF-32 BE/LE, UTF-8, and UTF-16 BE/LE BOM sequences at the start of each file.
  • Accumulate files containing BOMs and, if any are found, construct or update a bot comment on the PR (in Chinese) listing offending files, tagged with a hidden marker for idempotent updates, then mark the job as failed via core.setFailed.
.github/workflows/bom-check.yml
test.txt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - 我发现了两个问题,并给出了一些整体反馈:

  • 用于评论的 body 模板字符串在脚本块中有缩进,这会在发布的评论中引入前导空格/换行。建议将模板字符串内容左对齐,或者使用 trim() 来生成更干净的评论格式。
  • 在检测现有机器人评论时,你通过 comment.user.type === 'Bot' 进行过滤,这可能会遗漏来自 GitHub Apps 的评论;仅通过标记检查(或同时将 user.login 与 workflow 机器人账号比对)会让更新逻辑更健壮。
给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- 用于评论的 `body` 模板字符串在脚本块中有缩进,这会在发布的评论中引入前导空格/换行。建议将模板字符串内容左对齐,或者使用 `trim()` 来生成更干净的评论格式。
- 在检测现有机器人评论时,你通过 `comment.user.type === 'Bot'` 进行过滤,这可能会遗漏来自 GitHub Apps 的评论;仅通过标记检查(或同时将 `user.login` 与 workflow 机器人账号比对)会让更新逻辑更健壮。

## Individual Comments

### Comment 1
<location path=".github/workflows/bom-check.yml" line_range="4-5" />
<code_context>
+name: Check BOM in PR files
+
+on:
+  pull_request_target:
+    types: [opened, synchronize, reopened, ready_for_review]
+
+permissions:
</code_context>
<issue_to_address>
**🚨 issue (security):** Reconsider using `pull_request_target` given the permissions and untrusted PR context.

`pull_request_target` runs with a write-capable GITHUB_TOKEN on the base repo while using potentially untrusted fork code. Since this job posts comments and could grow over time, prefer `pull_request` unless you truly need `pull_request_target` (e.g., for secrets). If you keep it, please confirm that this event type is strictly required for your use case.
</issue_to_address>

### Comment 2
<location path=".github/workflows/bom-check.yml" line_range="77-88" />
<code_context>
+                continue;
+              }
+
+              const fd = fs.openSync(absolutePath, 'r');
+              const buffer = Buffer.alloc(4);
+              const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
+              fs.closeSync(fd);
+
+              const bom = detectBom(buffer.subarray(0, bytesRead));
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Wrap file descriptor operations to avoid leaks if an exception occurs during read.

If `fs.readSync` throws (e.g., due to a transient filesystem error), the file descriptor is never closed and will leak. Please wrap the open/read/close sequence in a `try`/`finally` so `fs.closeSync` always runs:

```js
let fd;
try {
  fd = fs.openSync(absolutePath, 'r');
  const buffer = Buffer.alloc(4);
  const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
  const bom = detectBom(buffer.subarray(0, bytesRead));
  // ...
} finally {
  if (fd !== undefined) {
    fs.closeSync(fd);
  }
}
```

```suggestion
              const absolutePath = path.join(workspace, file.filename);

              if (!fs.existsSync(absolutePath)) {
                continue;
              }

              let fd;
              let bom;
              try {
                fd = fs.openSync(absolutePath, 'r');
                const buffer = Buffer.alloc(4);
                const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
                bom = detectBom(buffer.subarray(0, bytesRead));
              } finally {
                if (fd !== undefined) {
                  fs.closeSync(fd);
                }
              }
```
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的 review 有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据这些反馈改进之后的 review。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • The body template literal for the comment is indented inside the script block, which will introduce leading spaces/newlines in the posted comment; consider left-aligning the template literal content or using trim() to produce cleaner comment formatting.
  • When detecting an existing bot comment you filter by comment.user.type === 'Bot', which may miss comments from GitHub Apps; checking for the marker alone (or also checking user.login against the workflow bot) would make the update logic more robust.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `body` template literal for the comment is indented inside the script block, which will introduce leading spaces/newlines in the posted comment; consider left-aligning the template literal content or using `trim()` to produce cleaner comment formatting.
- When detecting an existing bot comment you filter by `comment.user.type === 'Bot'`, which may miss comments from GitHub Apps; checking for the marker alone (or also checking `user.login` against the workflow bot) would make the update logic more robust.

## Individual Comments

### Comment 1
<location path=".github/workflows/bom-check.yml" line_range="4-5" />
<code_context>
+name: Check BOM in PR files
+
+on:
+  pull_request_target:
+    types: [opened, synchronize, reopened, ready_for_review]
+
+permissions:
</code_context>
<issue_to_address>
**🚨 issue (security):** Reconsider using `pull_request_target` given the permissions and untrusted PR context.

`pull_request_target` runs with a write-capable GITHUB_TOKEN on the base repo while using potentially untrusted fork code. Since this job posts comments and could grow over time, prefer `pull_request` unless you truly need `pull_request_target` (e.g., for secrets). If you keep it, please confirm that this event type is strictly required for your use case.
</issue_to_address>

### Comment 2
<location path=".github/workflows/bom-check.yml" line_range="77-88" />
<code_context>
+                continue;
+              }
+
+              const fd = fs.openSync(absolutePath, 'r');
+              const buffer = Buffer.alloc(4);
+              const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
+              fs.closeSync(fd);
+
+              const bom = detectBom(buffer.subarray(0, bytesRead));
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Wrap file descriptor operations to avoid leaks if an exception occurs during read.

If `fs.readSync` throws (e.g., due to a transient filesystem error), the file descriptor is never closed and will leak. Please wrap the open/read/close sequence in a `try`/`finally` so `fs.closeSync` always runs:

```js
let fd;
try {
  fd = fs.openSync(absolutePath, 'r');
  const buffer = Buffer.alloc(4);
  const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
  const bom = detectBom(buffer.subarray(0, bytesRead));
  // ...
} finally {
  if (fd !== undefined) {
    fs.closeSync(fd);
  }
}
```

```suggestion
              const absolutePath = path.join(workspace, file.filename);

              if (!fs.existsSync(absolutePath)) {
                continue;
              }

              let fd;
              let bom;
              try {
                fd = fs.openSync(absolutePath, 'r');
                const buffer = Buffer.alloc(4);
                const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
                bom = detectBom(buffer.subarray(0, bytesRead));
              } finally {
                if (fd !== undefined) {
                  fs.closeSync(fd);
                }
              }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +4 to +5
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚨 issue (security): 鉴于权限范围以及 PR 代码是不受信任的上下文,请重新考虑是否需要使用 pull_request_target

pull_request_target 会在基础仓库上使用具备写权限的 GITHUB_TOKEN 来运行,但执行的却可能是来自 fork 仓库的不受信任代码。由于这个工作流会发布评论并且未来可能扩展,除非你确实需要 pull_request_target(例如为了访问机密),否则更推荐使用 pull_request。如果你选择保留它,请确认该事件类型对你的用例是严格必需的。

Original comment in English

🚨 issue (security): Reconsider using pull_request_target given the permissions and untrusted PR context.

pull_request_target runs with a write-capable GITHUB_TOKEN on the base repo while using potentially untrusted fork code. Since this job posts comments and could grow over time, prefer pull_request unless you truly need pull_request_target (e.g., for secrets). If you keep it, please confirm that this event type is strictly required for your use case.

Comment on lines +77 to +88
const absolutePath = path.join(workspace, file.filename);

if (!fs.existsSync(absolutePath)) {
continue;
}

const fd = fs.openSync(absolutePath, 'r');
const buffer = Buffer.alloc(4);
const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
fs.closeSync(fd);

const bom = detectBom(buffer.subarray(0, bytesRead));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): 建议包装文件描述符相关操作,以避免在读取过程中发生异常时造成泄漏。

如果 fs.readSync 抛出异常(例如由于临时文件系统错误),文件描述符将不会被关闭并导致泄漏。请将 open/read/close 的调用序列包裹在 try/finally 中,以确保 fs.closeSync 始终会执行:

let fd;
try {
  fd = fs.openSync(absolutePath, 'r');
  const buffer = Buffer.alloc(4);
  const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
  const bom = detectBom(buffer.subarray(0, bytesRead));
  // ...
} finally {
  if (fd !== undefined) {
    fs.closeSync(fd);
  }
}
Suggested change
const absolutePath = path.join(workspace, file.filename);
if (!fs.existsSync(absolutePath)) {
continue;
}
const fd = fs.openSync(absolutePath, 'r');
const buffer = Buffer.alloc(4);
const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
fs.closeSync(fd);
const bom = detectBom(buffer.subarray(0, bytesRead));
const absolutePath = path.join(workspace, file.filename);
if (!fs.existsSync(absolutePath)) {
continue;
}
let fd;
let bom;
try {
fd = fs.openSync(absolutePath, 'r');
const buffer = Buffer.alloc(4);
const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
bom = detectBom(buffer.subarray(0, bytesRead));
} finally {
if (fd !== undefined) {
fs.closeSync(fd);
}
}
Original comment in English

suggestion (bug_risk): Wrap file descriptor operations to avoid leaks if an exception occurs during read.

If fs.readSync throws (e.g., due to a transient filesystem error), the file descriptor is never closed and will leak. Please wrap the open/read/close sequence in a try/finally so fs.closeSync always runs:

let fd;
try {
  fd = fs.openSync(absolutePath, 'r');
  const buffer = Buffer.alloc(4);
  const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
  const bom = detectBom(buffer.subarray(0, bytesRead));
  // ...
} finally {
  if (fd !== undefined) {
    fs.closeSync(fd);
  }
}
Suggested change
const absolutePath = path.join(workspace, file.filename);
if (!fs.existsSync(absolutePath)) {
continue;
}
const fd = fs.openSync(absolutePath, 'r');
const buffer = Buffer.alloc(4);
const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
fs.closeSync(fd);
const bom = detectBom(buffer.subarray(0, bytesRead));
const absolutePath = path.join(workspace, file.filename);
if (!fs.existsSync(absolutePath)) {
continue;
}
let fd;
let bom;
try {
fd = fs.openSync(absolutePath, 'r');
const buffer = Buffer.alloc(4);
const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
bom = detectBom(buffer.subarray(0, bytesRead));
} finally {
if (fd !== undefined) {
fs.closeSync(fd);
}
}

@Chiloven945 Chiloven945 deleted the testcibom branch May 9, 2026 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant