mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-16 06:06:54 +00:00
chore: publish from main
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
name: Contributor Reputation Check Writer
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Contributor Reputation Check"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
issues: write
|
||||
pull-requests: read
|
||||
|
||||
concurrency:
|
||||
group: ccw-${{ github.event.workflow_run.head_repository.id || 'unknown-repo' }}-${{ github.event.workflow_run.head_branch || 'unknown-branch' }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
sync-pr-state:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.workflow_run.event == 'pull_request'
|
||||
steps:
|
||||
- name: Download PR result artifact
|
||||
id: download-result
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: contributor-check-result
|
||||
path: ${{ runner.temp }}/contributor-check-result
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ github.token }}
|
||||
|
||||
- name: Sync risk labels and comment
|
||||
if: steps.download-result.outcome == 'success'
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const workflowRun = context.payload.workflow_run;
|
||||
const resultPath = path.join(process.env.RUNNER_TEMP, 'contributor-check-result', 'result.json');
|
||||
const raw = fs.readFileSync(resultPath, 'utf8');
|
||||
const result = JSON.parse(raw);
|
||||
const allowedRisks = new Set(['HIGH', 'MEDIUM', 'LOW', 'NONE', 'UNKNOWN']);
|
||||
|
||||
function fail(message) {
|
||||
throw new Error(`Invalid contributor check artifact: ${message}`);
|
||||
}
|
||||
|
||||
if (result.schema_version !== 'contributor-check-result/v1') fail('unexpected schema_version');
|
||||
if (result.event !== 'pull_request') fail('unexpected event');
|
||||
if (!Number.isInteger(result.pr_number) || result.pr_number < 1) fail('invalid pr_number');
|
||||
if (!/^[0-9a-f]{40}$/i.test(String(result.head_sha || ''))) fail('invalid head_sha');
|
||||
if (workflowRun.event !== 'pull_request') fail('unexpected workflow_run event');
|
||||
if (String(result.run_id || '') !== String(workflowRun.id)) fail('run_id did not match workflow_run');
|
||||
if (result.head_sha !== workflowRun.head_sha) fail('head_sha did not match workflow_run');
|
||||
for (const key of ['profile_risk', 'credential_risk', 'overall_risk']) {
|
||||
if (!allowedRisks.has(result[key])) fail(`invalid ${key}`);
|
||||
}
|
||||
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: result.pr_number,
|
||||
});
|
||||
|
||||
if (pr.state !== 'open') {
|
||||
core.info(`Skipping contributor result for non-open PR #${result.pr_number}.`);
|
||||
return;
|
||||
}
|
||||
const expectedBaseRepository = `${context.repo.owner}/${context.repo.repo}`.toLowerCase();
|
||||
const runHeadRepository = String(workflowRun.head_repository?.full_name || '');
|
||||
const runHeadRepositoryParts = runHeadRepository.split('/');
|
||||
const runHeadRef = String(workflowRun.head_branch || '');
|
||||
if (String(pr.base?.repo?.full_name || '').toLowerCase() !== expectedBaseRepository) {
|
||||
fail(`PR #${result.pr_number} does not target this repository`);
|
||||
}
|
||||
if (pr.head.sha !== workflowRun.head_sha) {
|
||||
core.warning(`Skipping stale contributor result for PR #${result.pr_number}: artifact head ${result.head_sha}, current head ${pr.head.sha}`);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
runHeadRepositoryParts.length !== 2 ||
|
||||
!runHeadRepositoryParts[0] ||
|
||||
!runHeadRepositoryParts[1] ||
|
||||
!runHeadRef ||
|
||||
String(pr.head?.repo?.full_name || '').toLowerCase() !== runHeadRepository.toLowerCase() ||
|
||||
String(pr.head?.ref || '') !== runHeadRef
|
||||
) {
|
||||
fail(`PR #${result.pr_number} head did not match workflow_run`);
|
||||
}
|
||||
|
||||
const workflowRunPullRequests = Array.isArray(workflowRun.pull_requests) ? workflowRun.pull_requests : [];
|
||||
if (workflowRunPullRequests.length > 0) {
|
||||
if (!workflowRunPullRequests.some((pullRequest) => pullRequest.number === result.pr_number)) {
|
||||
fail(`PR #${result.pr_number} was not present in workflow_run.pull_requests`);
|
||||
}
|
||||
} else {
|
||||
const candidatePullRequests = await github.paginate(github.rest.pulls.list, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
head: `${runHeadRepositoryParts[0]}:${runHeadRef}`,
|
||||
per_page: 100,
|
||||
});
|
||||
const trustedMatches = candidatePullRequests.filter((candidate) =>
|
||||
candidate.head?.sha === workflowRun.head_sha &&
|
||||
String(candidate.head?.ref || '') === runHeadRef &&
|
||||
String(candidate.head?.repo?.full_name || '').toLowerCase() === runHeadRepository.toLowerCase() &&
|
||||
String(candidate.base?.repo?.full_name || '').toLowerCase() === expectedBaseRepository
|
||||
);
|
||||
if (trustedMatches.length !== 1 || trustedMatches[0].number !== result.pr_number) {
|
||||
fail(`PR #${result.pr_number} could not be uniquely associated with workflow_run`);
|
||||
}
|
||||
}
|
||||
|
||||
const issueNumber = pr.number;
|
||||
const risk = result.overall_risk;
|
||||
const marker = '<!-- agt-contributor-check -->';
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
const matchingComments = comments.filter((comment) =>
|
||||
comment.user?.login === 'github-actions[bot]' && String(comment.body || '').includes(marker)
|
||||
);
|
||||
|
||||
if (risk !== 'MEDIUM' && risk !== 'HIGH') {
|
||||
for (const comment of matchingComments) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: comment.id,
|
||||
}).catch((error) => core.warning(`Could not delete comment ${comment.id}: ${error.message}`));
|
||||
}
|
||||
} else {
|
||||
const icon = risk === 'HIGH' ? '🔴' : '🟡';
|
||||
const runUrl = context.payload.workflow_run.html_url;
|
||||
const body = [
|
||||
marker,
|
||||
`${icon} **Contributor Reputation Check: ${risk} risk**`,
|
||||
'',
|
||||
'| Check | Risk |',
|
||||
'|-------|------|',
|
||||
`| Profile | ${result.profile_risk} |`,
|
||||
`| Credential audit | ${result.credential_risk} |`,
|
||||
'',
|
||||
'Maintainers: please review this contributor before merging.',
|
||||
`See the [workflow run](${runUrl}) for full details.`,
|
||||
'*Automated check powered by [AGT](https://github.com/microsoft/agent-governance-toolkit).*',
|
||||
].join('\n');
|
||||
|
||||
const [canonical, ...duplicates] = matchingComments;
|
||||
if (canonical) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: canonical.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
for (const duplicate of duplicates) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: duplicate.id,
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
for (const label of ['needs-review:MEDIUM', 'needs-review:HIGH']) {
|
||||
if (label !== `needs-review:${risk}`) {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
name: label,
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
if (risk === 'MEDIUM' || risk === 'HIGH') {
|
||||
const label = `needs-review:${risk}`;
|
||||
await github.rest.issues.getLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: label,
|
||||
}).catch(async () => {
|
||||
await github.rest.issues.createLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: label,
|
||||
description: `Contributor reputation check flagged ${risk} risk`,
|
||||
color: 'FFA500',
|
||||
});
|
||||
});
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
labels: [label],
|
||||
});
|
||||
}
|
||||
|
||||
- name: Note missing artifact
|
||||
if: steps.download-result.outcome != 'success'
|
||||
run: echo "No contributor-check-result artifact was available; nothing to synchronize."
|
||||
Reference in New Issue
Block a user