diff --git a/.github/workflows/clawsweeper-dispatch.yml b/.github/workflows/clawsweeper-dispatch.yml index efc07868ac15..0cccf7364fa6 100644 --- a/.github/workflows/clawsweeper-dispatch.yml +++ b/.github/workflows/clawsweeper-dispatch.yml @@ -289,6 +289,7 @@ jobs: env: GH_TOKEN: ${{ steps.token.outputs.token }} TARGET_REPO: ${{ github.repository }} + TARGET_BRANCH: ${{ github.event.repository.default_branch }} ITEM_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} ITEM_KIND: ${{ github.event_name == 'pull_request_target' && 'pull_request' || 'issue' }} SOURCE_EVENT: ${{ github.event_name }} @@ -299,14 +300,52 @@ jobs: exit 0 fi . "$RUNNER_TEMP/github-api-backoff.sh" + ingress_fingerprint="$(node <<'NODE' + const crypto = require("node:crypto"); + const fs = require("node:fs"); + const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8")); + const pullRequest = event.pull_request && typeof event.pull_request === "object" + ? event.pull_request + : {}; + const headSha = String(pullRequest.head?.sha || "").trim().toLowerCase(); + const updatedAt = String(pullRequest.updated_at || "").trim(); + if ( + process.env.ITEM_KIND !== "pull_request" || + !/^[0-9a-f]{40}$/.test(headSha) || + !updatedAt + ) { + process.stdout.write(""); + } else { + process.stdout.write( + crypto + .createHash("sha256") + .update( + JSON.stringify({ + version: 1, + target_repo: String(process.env.TARGET_REPO || "").toLowerCase(), + item_number: Number(process.env.ITEM_NUMBER), + action: String(process.env.SOURCE_ACTION || ""), + head_sha: headSha, + updated_at: updatedAt, + body: typeof pullRequest.body === "string" ? pullRequest.body : "", + label: String(event.label?.name || ""), + }), + ) + .digest("hex"), + ); + } + NODE + )" payload="$(jq -nc \ --arg target_repo "$TARGET_REPO" \ + --arg target_branch "$TARGET_BRANCH" \ --argjson item_number "$ITEM_NUMBER" \ --arg item_kind "$ITEM_KIND" \ --arg source_event "$SOURCE_EVENT" \ --arg source_action "$SOURCE_ACTION" \ + --arg ingress_fingerprint "$ingress_fingerprint" \ --argjson supersedes_in_progress "$SUPERSEDES_IN_PROGRESS" \ - '{event_type:"clawsweeper_item",client_payload:{target_repo:$target_repo,item_number:$item_number,item_kind:$item_kind,source_event:$source_event,source_action:$source_action,supersedes_in_progress:$supersedes_in_progress}}')" + '{event_type:"clawsweeper_item",client_payload:({target_repo:$target_repo,target_branch:$target_branch,item_number:$item_number,item_kind:$item_kind,source_event:$source_event,source_action:$source_action,supersedes_in_progress:$supersedes_in_progress} + (if $ingress_fingerprint != "" then {ingress_route:"target_dispatcher",ingress_fingerprint:$ingress_fingerprint} else {} end))}')" if gh_api_with_retry repos/openclaw/clawsweeper/dispatches \ --method POST \ --input - <<< "$payload"; then diff --git a/test/scripts/ci-workflow-guards.test.ts b/test/scripts/ci-workflow-guards.test.ts index 4e2bd214c4cd..b44510d92efd 100644 --- a/test/scripts/ci-workflow-guards.test.ts +++ b/test/scripts/ci-workflow-guards.test.ts @@ -1363,6 +1363,18 @@ NODE expect(activityRun).toMatch( /push: \(if \$event_name == "push" then \{\s+before: \.before,\s+after: \.after,\s+ref: \.ref,\s+compare: \.compare,\s+head_commit: \.head_commit\.id\s+\} else null end\)/u, ); + + const exactReviewStep = expectDefined( + steps.find((step) => step.name === "Dispatch exact ClawSweeper review"), + "ClawSweeper exact-review dispatch", + ); + expect(exactReviewStep.env?.TARGET_BRANCH).toBe( + "${{ github.event.repository.default_branch }}", + ); + expect(exactReviewStep.run).toContain('--arg target_branch "$TARGET_BRANCH"'); + expect(exactReviewStep.run).toContain("target_branch:$target_branch"); + expect(exactReviewStep.run).toContain('ingress_route:"target_dispatcher"'); + expect(exactReviewStep.run).toContain("ingress_fingerprint:$ingress_fingerprint"); }); it("runs the PR context and evidence gate only for relevant PR changes", () => {