Skip to content

fix: support fork PR intent comments - #205

Merged
z2z23n0 merged 1 commit into
mainfrom
fix/fork-pr-intent-action
Jul 27, 2026
Merged

fix: support fork PR intent comments#205
z2z23n0 merged 1 commit into
mainfrom
fix/fork-pr-intent-action

Conversation

@z2z23n0

@z2z23n0 z2z23n0 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Mainline Intent

Intent: int_807c5590
Status: proposed
Title: 为 Mainline PR Intent Action 增加 fork PR 支持

What changed

将 Mainline PR Intent workflow 迁移为单一 pull_request_target 路径:同仓 PR 继续 checkout 并执行 head 代码,fork PR 只 checkout 可信 base,并把 PR head 作为 Git 数据读取。pr-comment 新增可选的 fork URL/PR 参数,可从 fork actor refs 临时投影 contributor-published intents,复用原有 commit-range、多 intent、branch fallback、marker 和 sticky comment 行为。加入并发取消、head 新鲜度校验、live PR body 检查和临时 ref 清理,并补充 engine/CLI 回归测试。

Why

普通 pull_request 在 fork PR 上只有只读 token,无法写评论;直接移除同仓限制又会让高权限 job 执行不可信 fork 代码。新的可信 base 执行路径在不改变现有同仓评论能力的前提下安全读取 fork intent metadata,并避免在 review 阶段导入或修改 upstream Mainline 状态。

Decisions

  • GitHub Actions 触发与 checkout 模型: 使用单一 pull_request_target workflow;同仓 checkout head,fork checkout 精确 base SHA。 (保持一个稳定的 Mainline PR Intent check,避免 fork 同时出现旧 Skipped 和新 check;fork 路径始终只运行 default/base 上的可信代码。)
    • Rejected: 保留 pull_request 再新增 fork-only workflow,因为 GitHub 无法在 on 层按 head repo 过滤,会产生重复或 Skipped checks
  • fork intent metadata 的信任边界: 只把 fork actor refs fetch 到临时 imports refs 并物化只读 view;upstream canonical intent 同 ID 时始终优先。 (PR comment 是 review surface,不是 actor-log acceptance;预览不能调用 ImportActorLog、写 canonical actor refs/notes/view 或 push。)
    • Rejected: 在 PR 打开阶段复用 pr-import,因为它会接受 contributor metadata 并可能更新 upstream refs/notes
  • fork 与同仓评论语义: 复用现有 commit-range 优先、多 intent、branch fallback、排序和 Markdown renderer,并给未接受的 fork intent 增加 provenance 提示。 (reviewer 获得与同仓 PR 一致的 intent 内容,同时能区分 contributor-published metadata 尚未被 upstream 接受。)
  • 并发与过期事件处理: 按 PR 号取消旧 run,并在生成前后校验 live head/body。 (防止 synchronize/edited 的旧事件覆盖新评论;PR body 已有 Mainline marker 时直接清理旧 sticky comment 并成功退出。)

Subsystems: .github, cli, engine, github-actions, pull-request, intent-rendering, fork-actor-log

Copilot AI review requested due to automatic review settings July 27, 2026 09:58
@z2z23n0
z2z23n0 marked this pull request as ready for review July 27, 2026 10:02
@z2z23n0
z2z23n0 merged commit eb98131 into main Jul 27, 2026
8 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Mainline’s PR intent comment pipeline to safely support fork-based pull requests by shifting the GitHub Actions workflow to pull_request_target and adding an engine/CLI pathway that reads fork-published intent metadata as Git data without importing it into upstream state.

Changes:

  • Added PRCommentWithOptions and CLI flags (--pr, --fork-url) to render fork actor-log intent metadata in PR comments without syncing/importing.
  • Introduced fork intent discovery + rendering (including provenance messaging) and added targeted engine/CLI tests for fork behavior.
  • Migrated the Mainline PR Intent workflow to a single pull_request_target flow with concurrency cancellation and stale-head checks.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/engine/pr.go Adds PullRequestCommentOptions + fork-aware PR comment rendering entrypoint.
internal/engine/pr_fork.go Implements fork actor-log discovery/fetch and merges fork intents into PR comment view.
internal/engine/pr_fork_test.go Adds regression tests ensuring fork intent preview doesn’t import/accept upstream state and filters terminal intents.
internal/cli/pr.go Wires new pr-comment options (--pr, --fork-url) to the engine options struct.
internal/cli/root_test.go Ensures new pr-comment flags are registered.
.github/workflows/mainline-pr-intent.yml Switches to pull_request_target, adds concurrency, stale event checks, and fork-safe checkout/fetch strategy.
Comments suppressed due to low confidence (3)

internal/engine/pr_fork.go:121

  • Similarly, decoding failures for specific fork event payloads (sealed/abandoned/superseded) currently abort the entire PR comment generation. Since these payloads are also untrusted, treat decode failures as a skip for that event instead of failing the run.
		case domain.EventIntentSealed:
			var event domain.IntentSealedEvent
			if err := json.Unmarshal(raw, &event); err != nil {
				return nil, domain.NewError(
					domain.ErrInvalidInput,
					fmt.Sprintf("fork sealed event %s is invalid: %v", base.EventID, err),
				)
			}

internal/engine/pr_fork.go:133

  • For fork PR previews, an invalid abandoned event payload should not fail the entire PR intent comment generation (untrusted fork input). Skip malformed abandoned events instead.
		case domain.EventIntentAbandoned:
			var event domain.IntentAbandonedEvent
			if err := json.Unmarshal(raw, &event); err != nil {
				return nil, domain.NewError(
					domain.ErrInvalidInput,
					fmt.Sprintf("fork abandoned event %s is invalid: %v", base.EventID, err),
				)
			}

internal/engine/pr_fork.go:145

  • For fork PR previews, an invalid superseded event payload should not fail the entire PR intent comment generation (untrusted fork input). Skip malformed superseded events instead.
		case domain.EventIntentSuperseded:
			var event domain.IntentSupersededEvent
			if err := json.Unmarshal(raw, &event); err != nil {
				return nil, domain.NewError(
					domain.ErrInvalidInput,
					fmt.Sprintf("fork superseded event %s is invalid: %v", base.EventID, err),
				)
			}

Comment on lines +214 to +219
func forkPRCommentImportRef(actorID string, prNumber int) string {
if prNumber > 0 {
return fmt.Sprintf("refs/mainline/imports/pr-comments/pr-%d/%s/log", prNumber, actorID)
}
return "refs/mainline/imports/pr-comments/manual/" + actorID + "/log"
}
Comment on lines +100 to +108
intents := make(map[string]domain.IntentView)
for index, raw := range rawEvents {
var base domain.BaseEvent
if err := json.Unmarshal(raw, &base); err != nil {
return nil, domain.NewError(
domain.ErrInvalidInput,
fmt.Sprintf("fork actor log event %d is not valid JSON: %v", index, err),
)
}
Comment on lines +82 to +86
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
persist-credentials: false

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.

2 participants