Skip to content

ci(bom-check): 添加对 BOM 检测的 Action#2811

Closed
Chiloven945 wants to merge 6 commits into
PCL-Community:devfrom
Likos-Lupus:dev
Closed

ci(bom-check): 添加对 BOM 检测的 Action#2811
Chiloven945 wants to merge 6 commits into
PCL-Community:devfrom
Likos-Lupus:dev

Conversation

@Chiloven945
Copy link
Copy Markdown
Contributor

@Chiloven945 Chiloven945 commented May 9, 2026

Summary by Sourcery

CI:

  • 引入一个 GitHub Actions 工作流程,用于扫描 PR 中已修改的文件是否包含常见的 BOM 标记;一旦检测到就使检查失败,并在 PR 中发布或更新一条解释性评论。
Original summary in English

Summary by Sourcery

CI:

  • Introduce a GitHub Actions workflow that scans changed PR files for common BOM signatures and fails the check when any are detected, posting or updating an explanatory PR comment.

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

sourcery-ai Bot commented May 9, 2026

Reviewer's Guide

添加一个 GitHub Actions workflow,用于检查拉取请求(pull request)中文件变更是否包含 BOM 标记;如果检测到 BOM,则在 PR 上发布/更新机器人评论,并使检查失败以阻止合并。

pull_request 上 BOM 检测的时序图

sequenceDiagram
  actor Developer
  participant GitHub
  participant Workflow as Workflow_BOM_Check
  participant Job as Job_check_bom
  participant Checkout as Step_actions_checkout
  participant Script as Step_github_script
  participant API as GitHub_REST_API

  Developer->>GitHub: Open/update PR
  GitHub-->>Workflow: Trigger pull_request_target event

  Workflow->>Job: Start job check-bom (ubuntu-latest)

  Job->>Checkout: Run actions/checkout@v4
  Checkout-->>Job: PR head repo and SHA checked out

  Job->>Script: Run actions/github-script@v7

  Script->>API: pulls.listFiles(owner, repo, pull_number)
  API-->>Script: Changed file list

  loop For each non-removed changed file
    Script->>Script: Build absolute path in GITHUB_WORKSPACE
    Script->>Script: Read first 4 bytes via fs
    Script->>Script: detectBom(buffer)
    Script-->>Script: Record filename and BOM type if detected
  end

  alt No BOM found
    Script-->>Job: core.info("No BOM found")
    Job-->>Workflow: Succeeds
  else BOM found in at least one file
    Script->>API: issues.listComments(owner, repo, pull_number)
    API-->>Script: Existing comments

    Script->>Script: Find existing bot comment by marker

    alt Existing bot comment found
      Script->>API: issues.updateComment(comment_id, body)
    else No existing bot comment
      Script->>API: issues.createComment(issue_number, body)
    end

    Script-->>Job: core.setFailed("BOM found...")
    Job-->>Workflow: Mark job as failed
  end

  Workflow-->>GitHub: Report check status on PR
Loading

BOM 检测脚本逻辑的流程图

flowchart TD
  Start["Start github-script step"]
  Init["Init context: owner, repo, pull_number, workspace"]
  ListFiles["Call pulls.listFiles to get changed files"]
  InitFound["found = []"]

  Start --> Init --> ListFiles --> InitFound

  subgraph FileLoop["For each file in changedFiles"]
    CheckRemoved{Is file.status removed?}
    BuildPath["absolutePath = join(workspace, file.filename)"]
    CheckExists{Does file exist on disk?}
    ReadBytes["Read first 4 bytes via fs.readSync"]
    DetectBom["bom = detectBom(buffer)"]
    CheckBom{bom is not null?}
    PushFound["Push {filename, bom} into found"]

    CheckRemoved -->|Yes| NextFile
    CheckRemoved -->|No| BuildPath
    BuildPath --> CheckExists
    CheckExists -->|No| NextFile
    CheckExists -->|Yes| ReadBytes --> DetectBom --> CheckBom
    CheckBom -->|Yes| PushFound --> NextFile
    CheckBom -->|No| NextFile
  end

  InitFound --> FileLoop
  NextFile --> AfterLoop

  AfterLoop{found.length > 0?}
  AfterLoop -->|No| LogNoBom["core.info: No BOM found in changed PR files"] --> End

  AfterLoop -->|Yes| BuildBody["Build markdown body with marker and BOM file list"]

  ListComments["issues.listComments for PR"]
  FindExisting["Find existing bot comment containing marker"]
  HasExisting{Existing bot comment?}
  UpdateComment["issues.updateComment with new body"]
  CreateComment["issues.createComment with body"]
  FailCheck["core.setFailed: BOM found in changed PR files"]

  BuildBody --> ListComments --> FindExisting --> HasExisting
  HasExisting -->|Yes| UpdateComment --> FailCheck --> End
  HasExisting -->|No| CreateComment --> FailCheck --> End

  End["End github-script step"]
Loading

文件级变更

Change Details Files
引入一个 GitHub Actions workflow,用于检测 PR 中已变更文件里的 BOM,并通过 PR 评论报告这些 BOM;一旦发现 BOM,就使 workflow 失败。
  • 在 pull_request_target 事件上触发 workflow,覆盖 opened、synchronize、reopened 和 ready_for_review 状态
  • 检出拉取请求 head 仓库及其 SHA,且不持久化凭据
  • 使用 github-script 步骤列出 PR 中已变更文件(排除被删除的文件),并从工作区中读取每个文件的前几个字节
  • 实现对多种编码(UTF-8、UTF-16 LE/BE、UTF-32 LE/BE)的 BOM 检测,并收集所有发现 BOM 的文件
  • 在 PR 上构造或更新带有稳定隐藏标记的机器人评论,列出包含 BOM 的文件;一旦检测到任何 BOM,就将该 job 标记为失败
.github/workflows/bom-check.yml

Tips and commands

与 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 来触发新的评审!

自定义你的体验

访问你的 dashboard 以:

  • 启用或禁用评审功能,例如 Sourcery 自动生成的拉取请求总结、评审者指南等。
  • 更改评审语言。
  • 添加、移除或编辑自定义评审指令。
  • 调整其他评审设置。

获取帮助

Original review guide in English

Reviewer's Guide

Adds a GitHub Actions workflow that checks pull request file changes for the presence of BOM markers and posts/updates a bot comment on the PR when BOMs are detected, failing the check to block merging.

Sequence diagram for BOM detection on pull_request

sequenceDiagram
  actor Developer
  participant GitHub
  participant Workflow as Workflow_BOM_Check
  participant Job as Job_check_bom
  participant Checkout as Step_actions_checkout
  participant Script as Step_github_script
  participant API as GitHub_REST_API

  Developer->>GitHub: Open/update PR
  GitHub-->>Workflow: Trigger pull_request_target event

  Workflow->>Job: Start job check-bom (ubuntu-latest)

  Job->>Checkout: Run actions/checkout@v4
  Checkout-->>Job: PR head repo and SHA checked out

  Job->>Script: Run actions/github-script@v7

  Script->>API: pulls.listFiles(owner, repo, pull_number)
  API-->>Script: Changed file list

  loop For each non-removed changed file
    Script->>Script: Build absolute path in GITHUB_WORKSPACE
    Script->>Script: Read first 4 bytes via fs
    Script->>Script: detectBom(buffer)
    Script-->>Script: Record filename and BOM type if detected
  end

  alt No BOM found
    Script-->>Job: core.info("No BOM found")
    Job-->>Workflow: Succeeds
  else BOM found in at least one file
    Script->>API: issues.listComments(owner, repo, pull_number)
    API-->>Script: Existing comments

    Script->>Script: Find existing bot comment by marker

    alt Existing bot comment found
      Script->>API: issues.updateComment(comment_id, body)
    else No existing bot comment
      Script->>API: issues.createComment(issue_number, body)
    end

    Script-->>Job: core.setFailed("BOM found...")
    Job-->>Workflow: Mark job as failed
  end

  Workflow-->>GitHub: Report check status on PR
Loading

Flow diagram for BOM detection script logic

flowchart TD
  Start["Start github-script step"]
  Init["Init context: owner, repo, pull_number, workspace"]
  ListFiles["Call pulls.listFiles to get changed files"]
  InitFound["found = []"]

  Start --> Init --> ListFiles --> InitFound

  subgraph FileLoop["For each file in changedFiles"]
    CheckRemoved{Is file.status removed?}
    BuildPath["absolutePath = join(workspace, file.filename)"]
    CheckExists{Does file exist on disk?}
    ReadBytes["Read first 4 bytes via fs.readSync"]
    DetectBom["bom = detectBom(buffer)"]
    CheckBom{bom is not null?}
    PushFound["Push {filename, bom} into found"]

    CheckRemoved -->|Yes| NextFile
    CheckRemoved -->|No| BuildPath
    BuildPath --> CheckExists
    CheckExists -->|No| NextFile
    CheckExists -->|Yes| ReadBytes --> DetectBom --> CheckBom
    CheckBom -->|Yes| PushFound --> NextFile
    CheckBom -->|No| NextFile
  end

  InitFound --> FileLoop
  NextFile --> AfterLoop

  AfterLoop{found.length > 0?}
  AfterLoop -->|No| LogNoBom["core.info: No BOM found in changed PR files"] --> End

  AfterLoop -->|Yes| BuildBody["Build markdown body with marker and BOM file list"]

  ListComments["issues.listComments for PR"]
  FindExisting["Find existing bot comment containing marker"]
  HasExisting{Existing bot comment?}
  UpdateComment["issues.updateComment with new body"]
  CreateComment["issues.createComment with body"]
  FailCheck["core.setFailed: BOM found in changed PR files"]

  BuildBody --> ListComments --> FindExisting --> HasExisting
  HasExisting -->|Yes| UpdateComment --> FailCheck --> End
  HasExisting -->|No| CreateComment --> FailCheck --> End

  End["End github-script step"]
Loading

File-Level Changes

Change Details Files
Introduce a GitHub Actions workflow to detect BOMs in changed PR files and report them via PR comments while failing the workflow when BOMs are found.
  • Trigger workflow on pull_request_target events for opened, synchronize, reopened, and ready_for_review
  • Check out the pull request head repository and SHA without persisting credentials
  • Use a github-script step to list changed files in the PR, excluding removed files, and read the first few bytes of each file from the workspace
  • Implement BOM detection for multiple encodings (UTF-8, UTF-16 LE/BE, UTF-32 LE/BE) and collect files where a BOM is found
  • Construct or update a bot comment on the PR with a stable hidden marker listing files containing BOMs, and mark the job as failed when any BOM is detected
.github/workflows/bom-check.yml

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 - 我发现了两个问题,并提供了一些宏观层面的反馈:

  • pull_request_target 与 PR head(repository + ref)的 actions/checkout 搭配使用,会在 base 仓库上下文中运行来自 fork 的不受信任代码;建议改用 pull_request,或者增加显式的安全加固措施(例如仅发表评论,对 fork 的 PR 不执行代码),以避免权限提升风险。
  • 当前的 BOM 检查会在所有变更文件上运行,包括潜在的二进制资源文件;建议按文件扩展名或 file.status/file.additions 等启发式方式过滤,只扫描文本类文件,从而避免在二进制文件上出现噪声式的失败。
提供给 AI Agent 的提示词
Please address the comments from this code review:

## Overall Comments
-`pull_request_target` 与 PR head(`repository` + `ref`)的 `actions/checkout` 搭配使用,会在 base 仓库上下文中运行来自 fork 的不受信任代码;建议改用 `pull_request`,或者增加显式的安全加固措施(例如仅发表评论,对 fork 的 PR 不执行代码),以避免权限提升风险。
- 当前的 BOM 检查会在所有变更文件上运行,包括潜在的二进制资源文件;建议按文件扩展名或 `file.status`/`file.additions` 等启发式方式过滤,只扫描文本类文件,从而避免在二进制文件上出现噪声式的失败。

## Individual Comments

### Comment 1
<location path=".github/workflows/bom-check.yml" line_range="83-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));
+
+              if (bom) {
</code_context>
<issue_to_address>
**issue (bug_risk):** 使用 try/finally 来保护 `openSync`/`readSync`/`closeSync`,以避免在发生错误时泄漏文件描述符(FD)。

如果 `fs.readSync``detectBom` 抛出异常(例如瞬时文件系统错误),循环会在没有执行 `fs.closeSync(fd)` 的情况下退出,随着时间推移会导致文件描述符泄漏。请将读取和 BOM 检测逻辑包裹在 `try`/`finally` 中,以确保文件描述符总是会被关闭:

```js
const fd = fs.openSync(absolutePath, 'r');
try {
  const buffer = Buffer.alloc(4);
  const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
  const bom = detectBom(buffer.subarray(0, bytesRead));
  if (bom) {
    found.push({ filename: file.filename, bom });
  }
} finally {
  fs.closeSync(fd);
}
```
</issue_to_address>

### Comment 2
<location path=".github/workflows/bom-check.yml" line_range="107-111" />
<code_context>
+              .map(item => `- \`${item.filename}\`:${item.bom}`)
+              .join('\n');
+
+            const body = `${marker}
+            发现以下 PR 变更文件存在 BOM,请移除后重新提交:
+
+            ${fileList}
+            `;
+
+            const comments = await github.paginate(
</code_context>
<issue_to_address>
**nitpick:** 对模板字符串进行 `trim` 处理或左对齐,以避免在评论中产生意外的前导空格。

由于模板字符串为了配合 YAML 缩进而进行了缩进,发布后的评论中每一行都会以多余的空格开头,这可能会改变 Markdown 的渲染效果(比如被渲染成代码块)。建议将字符串左对齐,或在 `body` 上调用 `trim()`,以确保最终渲染出的评论格式符合预期。
</issue_to_address>

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

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

  • Using pull_request_target with actions/checkout of the PR head (repository + ref) runs untrusted fork code in the base repo context; consider either switching to pull_request or adding explicit hardening (e.g., only commenting, no code execution on forked PRs) to avoid privilege escalation risks.
  • The BOM check currently runs on all changed files, including potential binary assets; consider filtering by file extension or file.status/file.additions heuristics so that only text-like files are scanned and you avoid noisy failures on binaries.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Using `pull_request_target` with `actions/checkout` of the PR head (`repository` + `ref`) runs untrusted fork code in the base repo context; consider either switching to `pull_request` or adding explicit hardening (e.g., only commenting, no code execution on forked PRs) to avoid privilege escalation risks.
- The BOM check currently runs on all changed files, including potential binary assets; consider filtering by file extension or `file.status`/`file.additions` heuristics so that only text-like files are scanned and you avoid noisy failures on binaries.

## Individual Comments

### Comment 1
<location path=".github/workflows/bom-check.yml" line_range="83-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));
+
+              if (bom) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard `openSync`/`readSync`/`closeSync` with try/finally to avoid leaking FDs on errors.

If `fs.readSync` or `detectBom` throws (e.g. transient FS error), the loop exits without `fs.closeSync(fd)`, leaking file descriptors over time. Wrap the read/BOM detection in a `try`/`finally` so the descriptor is always closed:

```js
const fd = fs.openSync(absolutePath, 'r');
try {
  const buffer = Buffer.alloc(4);
  const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
  const bom = detectBom(buffer.subarray(0, bytesRead));
  if (bom) {
    found.push({ filename: file.filename, bom });
  }
} finally {
  fs.closeSync(fd);
}
```
</issue_to_address>

### Comment 2
<location path=".github/workflows/bom-check.yml" line_range="107-111" />
<code_context>
+              .map(item => `- \`${item.filename}\`:${item.bom}`)
+              .join('\n');
+
+            const body = `${marker}
+            发现以下 PR 变更文件存在 BOM,请移除后重新提交:
+
+            ${fileList}
+            `;
+
+            const comments = await github.paginate(
</code_context>
<issue_to_address>
**nitpick:** Trim or left-align the template literal to avoid unintended leading whitespace in the comment.

Because the template literal is indented to match the YAML, each line of the posted comment will start with extra spaces, which can change Markdown rendering (e.g., turning it into a code block). Consider left-aligning the string or calling `trim()` on `body` so the rendered comment has the expected formatting.
</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 thread .github/workflows/bom-check.yml Outdated
Comment thread .github/workflows/bom-check.yml Outdated
@Chiloven945
Copy link
Copy Markdown
Contributor Author

觉得还是交给 pclce-automation 比较好🤔

@Chiloven945 Chiloven945 closed this May 9, 2026
@pcl-ce-automation pcl-ce-automation Bot removed 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: L PR 大小评估:大型 labels May 9, 2026
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