chore(workflows): label vouched users and restrict vouch managers (#15075)

This commit is contained in:
Ryan Vogel
2026-02-25 09:42:52 -05:00
committed by opencode
parent 5e5823ed85
commit e48c1ccf07
3 changed files with 78 additions and 36 deletions

View File

@@ -42,15 +42,17 @@ jobs:
throw error; throw error;
} }
// Parse the .td file for denounced users // Parse the .td file for vouched and denounced users
const vouched = new Set();
const denounced = new Map(); const denounced = new Map();
for (const line of content.split('\n')) { for (const line of content.split('\n')) {
const trimmed = line.trim(); const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue; if (!trimmed || trimmed.startsWith('#')) continue;
if (!trimmed.startsWith('-')) continue;
const rest = trimmed.slice(1).trim(); const isDenounced = trimmed.startsWith('-');
const rest = isDenounced ? trimmed.slice(1).trim() : trimmed;
if (!rest) continue; if (!rest) continue;
const spaceIdx = rest.indexOf(' '); const spaceIdx = rest.indexOf(' ');
const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx); const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx);
const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim(); const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim();
@@ -65,32 +67,50 @@ jobs:
const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1); const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1);
if (!username) continue; if (!username) continue;
denounced.set(username.toLowerCase(), reason); if (isDenounced) {
denounced.set(username.toLowerCase(), reason);
continue;
}
vouched.add(username.toLowerCase());
} }
// Check if the author is denounced // Check if the author is denounced
const reason = denounced.get(author.toLowerCase()); const reason = denounced.get(author.toLowerCase());
if (reason === undefined) { if (reason !== undefined) {
core.info(`User ${author} is not denounced. Allowing issue.`); // Author is denounced — close the issue
const body = 'This issue has been automatically closed.';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body,
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
state: 'closed',
state_reason: 'not_planned',
});
core.info(`Closed issue #${issueNumber} from denounced user ${author}`);
return; return;
} }
// Author is denounced — close the issue // Author is positively vouched — add label
const body = 'This issue has been automatically closed.'; if (!vouched.has(author.toLowerCase())) {
core.info(`User ${author} is not denounced or vouched. Allowing issue.`);
return;
}
await github.rest.issues.createComment({ await github.rest.issues.addLabels({
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
issue_number: issueNumber, issue_number: issueNumber,
body, labels: ['Vouched'],
}); });
await github.rest.issues.update({ core.info(`Added vouched label to issue #${issueNumber} from ${author}`);
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
state: 'closed',
state_reason: 'not_planned',
});
core.info(`Closed issue #${issueNumber} from denounced user ${author}`);

View File

@@ -6,6 +6,7 @@ on:
permissions: permissions:
contents: read contents: read
issues: write
pull-requests: write pull-requests: write
jobs: jobs:
@@ -42,15 +43,17 @@ jobs:
throw error; throw error;
} }
// Parse the .td file for denounced users // Parse the .td file for vouched and denounced users
const vouched = new Set();
const denounced = new Map(); const denounced = new Map();
for (const line of content.split('\n')) { for (const line of content.split('\n')) {
const trimmed = line.trim(); const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue; if (!trimmed || trimmed.startsWith('#')) continue;
if (!trimmed.startsWith('-')) continue;
const rest = trimmed.slice(1).trim(); const isDenounced = trimmed.startsWith('-');
const rest = isDenounced ? trimmed.slice(1).trim() : trimmed;
if (!rest) continue; if (!rest) continue;
const spaceIdx = rest.indexOf(' '); const spaceIdx = rest.indexOf(' ');
const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx); const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx);
const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim(); const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim();
@@ -65,29 +68,47 @@ jobs:
const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1); const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1);
if (!username) continue; if (!username) continue;
denounced.set(username.toLowerCase(), reason); if (isDenounced) {
denounced.set(username.toLowerCase(), reason);
continue;
}
vouched.add(username.toLowerCase());
} }
// Check if the author is denounced // Check if the author is denounced
const reason = denounced.get(author.toLowerCase()); const reason = denounced.get(author.toLowerCase());
if (reason === undefined) { if (reason !== undefined) {
core.info(`User ${author} is not denounced. Allowing PR.`); // Author is denounced — close the PR
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: 'This pull request has been automatically closed.',
});
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
state: 'closed',
});
core.info(`Closed PR #${prNumber} from denounced user ${author}`);
return; return;
} }
// Author is denounced — close the PR // Author is positively vouched — add label
await github.rest.issues.createComment({ if (!vouched.has(author.toLowerCase())) {
core.info(`User ${author} is not denounced or vouched. Allowing PR.`);
return;
}
await github.rest.issues.addLabels({
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
issue_number: prNumber, issue_number: prNumber,
body: 'This pull request has been automatically closed.', labels: ['Vouched'],
}); });
await github.rest.pulls.update({ core.info(`Added vouched label to PR #${prNumber} from ${author}`);
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
state: 'closed',
});
core.info(`Closed PR #${prNumber} from denounced user ${author}`);

View File

@@ -33,5 +33,6 @@ jobs:
with: with:
issue-id: ${{ github.event.issue.number }} issue-id: ${{ github.event.issue.number }}
comment-id: ${{ github.event.comment.id }} comment-id: ${{ github.event.comment.id }}
roles: admin,maintain
env: env:
GITHUB_TOKEN: ${{ steps.committer.outputs.token }} GITHUB_TOKEN: ${{ steps.committer.outputs.token }}