Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 32 additions & 25 deletions .agents/skills/nemoclaw-maintainer-day/scripts/check-gates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1865,6 +1865,29 @@ function currentCheckRollup(
return { runId: segments[4], jobId: segments[6] };
};

const associationLessHeadBinding = (
metadata: ActionRunMetadata,
): "current" | "other" | "unknown" => {
if (
metadata.hasPullRequests !== false ||
(metadata.event !== "pull_request" && metadata.event !== "pull_request_target")
) {
return "unknown";
}
if (
metadata.headShaMatches === false ||
metadata.headRefNameMatches === false ||
metadata.headRepositoryMatches === false
) {
return "other";
}
return metadata.headShaMatches === true &&
metadata.headRefNameMatches === true &&
metadata.headRepositoryMatches === true
? "current"
: "unknown";
};

const isAuthenticatedAdvisoryPrReviewCheck = (check: StatusCheck): boolean => {
const checkName = check.name ?? "";
if (
Expand All @@ -1880,13 +1903,20 @@ function currentCheckRollup(
const job = latestAttemptJobs(identity.runId)?.get(identity.jobId);
const checkStatus = check.status?.toUpperCase() ?? null;
const checkConclusion = check.conclusion?.toUpperCase() ?? null;
const currentPrBinding =
run?.hasPullRequests === true && run.exactDiff === true
? true
: exactDiff.headRepository !== repo &&
run !== null &&
run.status === "COMPLETED" &&
run.conclusion !== null &&
associationLessHeadBinding(run) === "current";
return Boolean(
run &&
job &&
run.event === "pull_request_target" &&
run.path === PR_REVIEW_ADVISOR_WORKFLOW_PATH &&
run.hasPullRequests === true &&
run.exactDiff === true &&
currentPrBinding &&
job.name === checkName &&
job.status === checkStatus &&
job.conclusion === checkConclusion,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand All @@ -1899,29 +1929,6 @@ function currentCheckRollup(
check.detailsUrl?.match(/\/runs\/(\d+)(?:[/?#]|$)/u)?.[1] ===
String(e2eCoordinationEvidence.trustedCustomCheckId);

const associationLessHeadBinding = (
metadata: ActionRunMetadata,
): "current" | "other" | "unknown" => {
if (
metadata.hasPullRequests !== false ||
(metadata.event !== "pull_request" && metadata.event !== "pull_request_target")
) {
return "unknown";
}
if (
metadata.headShaMatches === false ||
metadata.headRefNameMatches === false ||
metadata.headRepositoryMatches === false
) {
return "other";
}
return metadata.headShaMatches === true &&
metadata.headRefNameMatches === true &&
metadata.headRepositoryMatches === true
? "current"
: "unknown";
};

function runIdentityEvidence(
runId: string,
requiresExactDiff: boolean,
Expand Down
98 changes: 98 additions & 0 deletions test/skills/check-gates-actions-evidence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ interface AdvisorRunOptions {
jobName?: string;
path?: string;
event?: string;
headSha?: string;
headBranch?: string;
headRepository?: string;
pullRequests?: unknown[];
status?: string;
conclusion?: string | null;
Expand Down Expand Up @@ -165,6 +168,101 @@ describe("maintainer merge-gate contributor compliance", () => {
});
});

it("keeps a current fork Advisor lane advisory without a REST PR association", () => {
const runId = 9003;
const jobId = 9103;
const forkRepository = "contributor/NemoClaw";
const result = runGate({
body: "Signed-off-by: Example User <user@example.com>",
verified: true,
headRepository: forkRepository,
statusChecks: [...successfulRequiredChecks(), advisorCheck(runId, jobId)],
actionRunAttempts: {
[String(runId)]: advisorRun(jobId, {
headSha: HEAD_SHA,
headBranch: "feature-branch",
headRepository: forkRepository,
pullRequests: [],
status: "completed",
conclusion: "failure",
}),
},
});

expect(JSON.parse(result.stdout)).toMatchObject({
allPass: true,
gates: { ci: { pass: true } },
});
});

it.each([
{
evidence: "the workflow run is in progress",
run: { status: "in_progress", conclusion: "failure" },
},
{
evidence: "the completed workflow run has no conclusion",
run: { status: "completed", conclusion: null },
},
])("keeps an association-less fork Advisor lane merge-relevant when $evidence", ({ run }) => {
const runId = 9005;
const jobId = 9105;
const forkRepository = "contributor/NemoClaw";
const result = runGate({
body: "Signed-off-by: Example User <user@example.com>",
verified: true,
headRepository: forkRepository,
statusChecks: [...successfulRequiredChecks(), advisorCheck(runId, jobId)],
actionRunAttempts: {
[String(runId)]: advisorRun(jobId, {
headSha: HEAD_SHA,
headBranch: "feature-branch",
headRepository: forkRepository,
pullRequests: [],
...run,
}),
},
});

expect(JSON.parse(result.stdout)).toMatchObject({
allPass: false,
gates: { ci: { pass: false } },
});
});

it.each([
{ evidence: "the head SHA differs", run: { headSha: BASE_SHA } },
{ evidence: "the head ref differs", run: { headBranch: "other-branch" } },
{
evidence: "the head repository differs",
run: { headRepository: "attacker/NemoClaw" },
},
])("keeps an association-less fork Advisor lane merge-relevant when $evidence", ({ run }) => {
const runId = 9004;
const jobId = 9104;
const forkRepository = "contributor/NemoClaw";
const result = runGate({
body: "Signed-off-by: Example User <user@example.com>",
verified: true,
headRepository: forkRepository,
statusChecks: [...successfulRequiredChecks(), advisorCheck(runId, jobId)],
actionRunAttempts: {
[String(runId)]: advisorRun(jobId, {
headSha: HEAD_SHA,
headBranch: "feature-branch",
headRepository: forkRepository,
pullRequests: [],
...run,
}),
},
});

expect(JSON.parse(result.stdout)).toMatchObject({
allPass: false,
gates: { ci: { pass: false } },
});
});

it.each([
{ evidence: "the REST job has another name", run: { jobName: "unrelated job" } },
{
Expand Down
Loading