Skip to content

Commit 69713b7

Browse files
committed
Remove signature pagination limit
1 parent 6691cb7 commit 69713b7

1 file changed

Lines changed: 39 additions & 41 deletions

File tree

.github/workflows/check-signature.yaml

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ on:
1414
required: true
1515
type: number
1616

17-
permissions: {} # Restrict token access to the minimum required for this workflow
17+
permissions: {}
1818

1919
jobs:
2020
verify:
@@ -31,24 +31,29 @@ jobs:
3131
PR_NUMBER: ${{ inputs.pr_number }}
3232
with:
3333
script: |
34-
// Enforce strictly typed parameter input to prevent code injection
3534
const prNumber = Number(process.env.PR_NUMBER);
3635
if (!Number.isInteger(prNumber) || prNumber <= 0) {
3736
core.setFailed("Invalid PR number input context (expected a positive integer).");
3837
return;
3938
}
4039
4140
const commentIdentifier = "<!-- id: growss-signature-gate-bot-comment -->";
41+
const owner = context.repo.owner;
42+
const repo = context.repo.repo;
4243
4344
// 1. Fetch verification status of all PR commits using GraphQL API
44-
const query = `
45-
query($owner: String!, $repo: String!, $pr: Int!) {
45+
const unverifiedCommits = [];
46+
let hasNextPage = true;
47+
let cursor = null;
48+
49+
const commitQuery = `
50+
query($owner: String!, $repo: String!, $pr: Int!, $cursor: String) {
4651
repository(owner: $owner, name: $repo) {
4752
pullRequest(number: $pr) {
48-
commits(first: 100) {
49-
totalCount
53+
commits(first: 100, after: $cursor) {
5054
pageInfo {
5155
hasNextPage
56+
endCursor
5257
}
5358
nodes {
5459
commit {
@@ -64,68 +69,61 @@ jobs:
6469
}
6570
`;
6671
67-
const variables = {
68-
owner: context.repo.owner,
69-
repo: context.repo.repo,
70-
pr: prNumber
71-
};
72+
while (hasNextPage) {
73+
const result = await github.graphql(commitQuery, { owner, repo, pr: prNumber, cursor });
74+
const connection = result.repository.pullRequest.commits;
7275
73-
const result = await github.graphql(query, variables);
74-
const commitsConnection = result.repository.pullRequest.commits;
75-
const commits = commitsConnection.nodes;
76+
// Process batch and keep only unverified commits in memory
77+
for (const node of connection.nodes) {
78+
if (!node.commit.signature || !node.commit.signature.isValid) {
79+
unverifiedCommits.push({ oid: node.commit.oid });
80+
}
81+
}
7682
77-
// Fail closed if PR exceeds max single-page limits (100 commits)
78-
if (commitsConnection.pageInfo.hasNextPage || commitsConnection.totalCount > 100) {
79-
core.setFailed(`PR block: Pull Request contains too many commits (${commitsConnection.totalCount}). Maximum supported limit for an automated verification run is 100 commits.`);
80-
return;
83+
hasNextPage = connection.pageInfo.hasNextPage;
84+
cursor = connection.pageInfo.endCursor;
8185
}
8286
83-
// 2. Identify unverified commits (unsigned or signature validation failed)
84-
const unverifiedCommits = commits.filter(c => !c.commit.signature || !c.commit.signature.isValid);
85-
86-
// 3. Scan for an existing bot comment to update or delete
87-
const comments = await github.rest.issues.listComments({
88-
owner: context.repo.owner,
89-
repo: context.repo.repo,
90-
issue_number: prNumber,
91-
per_page: 100
92-
});
87+
// The 3rd parameter runs for each page, stripping heavy metadata arrays instantly
88+
const matchingComments = await github.paginate(
89+
github.rest.issues.listComments,
90+
{ owner, repo, issue_number: prNumber, per_page: 100 },
91+
(page) => page.data
92+
.filter(c => c.body && c.body.includes(commentIdentifier))
93+
.map(c => ({ id: c.id, body: c.body })) // Save only ID & body properties
94+
);
9395
94-
const existingComment = comments.data.find(c => c.body.includes(commentIdentifier));
96+
// Since our filter/map only targets matched elements, grab the first element if it exists
97+
const existingComment = matchingComments[0] || null;
9598
96-
// 4. Handle logic based on validation state
9799
if (unverifiedCommits.length > 0) {
98-
const commitList = unverifiedCommits.map(c => `- \`${c.commit.oid.substring(0, 7)}\``).join('\n');
100+
const commitList = unverifiedCommits.map(c => `- \`${c.oid.substring(0, 7)}\``).join('\n');
99101
const commentBody = `${commentIdentifier}\n ⚠️ **Unverified Commits Detected**\n\nThe following commits in this Pull Request are missing a verified cryptographic signature:\n\n${commitList}\n\nPlease sign your commits to comply with <a href="https://metoffice.github.io/simulation-systems/WorkingPractices/gh_authorisation.html#verified-commits">project guidelines</a>.`;
100102
101103
if (existingComment) {
102-
// Update the old comment with the refreshed list of unverified commits
103104
await github.rest.issues.updateComment({
104-
owner: context.repo.owner,
105-
repo: context.repo.repo,
105+
owner,
106+
repo,
106107
comment_id: existingComment.id,
107108
body: commentBody
108109
});
109110
} else {
110-
// Post a new warning comment
111111
await github.rest.issues.createComment({
112-
owner: context.repo.owner,
113-
repo: context.repo.repo,
112+
owner,
113+
repo,
114114
issue_number: prNumber,
115115
body: commentBody
116116
});
117117
}
118118
119-
// Force the CI status check to fail outright
120119
core.setFailed("PR block: One or more commits do not have a verified signature.");
121120
return;
122121
123122
} else {
124-
// All commits are signed! Clear old warning comment if it exists
125123
if (existingComment) {
126124
await github.rest.issues.deleteComment({
127-
owner: context.repo.owner,
128-
repo: context.repo.repo,
125+
owner,
126+
repo,
129127
comment_id: existingComment.id
130128
});
131129
console.log("::notice::Clean state achieved: Deleted the old signature warning comment.");

0 commit comments

Comments
 (0)