mirror of
https://github.com/ChrisTitusTech/winutil
synced 2026-06-04 14:17:27 +00:00
543b8958ef
* Initial plan * Fix Actions script injection vulnerability in issue-slash-commands.yaml Agent-Logs-Url: https://github.com/ChrisTitusTech/winutil/sessions/94895aac-198f-40b6-af42-27fe0c646587 Co-authored-by: ChrisTitusTech <7896101+ChrisTitusTech@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ChrisTitusTech <7896101+ChrisTitusTech@users.noreply.github.com>
78 lines
2.9 KiB
YAML
78 lines
2.9 KiB
YAML
name: Issue slash commands
|
|
|
|
on:
|
|
issue_comment:
|
|
types: [created, edited]
|
|
|
|
jobs:
|
|
issueCommands:
|
|
# Skip this job if the comment was created/edited on a PR
|
|
if: ${{ !github.event.issue.pull_request }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
issues: write
|
|
pull-requests: none
|
|
contents: read
|
|
|
|
steps:
|
|
- name: Process slash command
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const allowedUsers = ["ChrisTitusTech", "og-mrk", "Marterich", "MyDrift-user", "Real-MullaC", "CodingWonders", "GabiNun2", "FluffyPunk"];
|
|
const commenter = context.payload.comment.user.login;
|
|
|
|
// Authorization check first — before any parsing of comment content
|
|
if (!allowedUsers.includes(commenter)) {
|
|
console.log(`User ${commenter} is not in the allowlist. Skipping.`);
|
|
return;
|
|
}
|
|
|
|
// Read comment body as data, never interpolated into shell
|
|
const body = context.payload.comment.body;
|
|
const issueNumber = context.issue.number;
|
|
const owner = context.repo.owner;
|
|
const repo = context.repo.repo;
|
|
|
|
// /label 'name' or /label name
|
|
const labelMatch = body.match(/\/label\s+'([^']+)'|\/label\s+(\S+?)(?:\s|$)/);
|
|
if (labelMatch) {
|
|
const labelName = (labelMatch[1] || labelMatch[2]).trim();
|
|
console.log(`Adding label: ${labelName}`);
|
|
await github.rest.issues.addLabels({
|
|
owner, repo, issue_number: issueNumber,
|
|
labels: [labelName],
|
|
});
|
|
}
|
|
|
|
// /unlabel 'name' or /unlabel name
|
|
const unlabelMatch = body.match(/\/unlabel\s+'([^']+)'|\/unlabel\s+(\S+?)(?:\s|$)/);
|
|
if (unlabelMatch) {
|
|
const labelName = (unlabelMatch[1] || unlabelMatch[2]).trim();
|
|
console.log(`Removing label: ${labelName}`);
|
|
await github.rest.issues.removeLabel({
|
|
owner, repo, issue_number: issueNumber,
|
|
name: labelName,
|
|
});
|
|
}
|
|
|
|
// /close (optionally with 'not planned')
|
|
if (body.includes('/close')) {
|
|
const stateReason = body.includes('not planned') ? 'not_planned' : 'completed';
|
|
console.log(`Closing issue (reason: ${stateReason})`);
|
|
await github.rest.issues.update({
|
|
owner, repo, issue_number: issueNumber,
|
|
state: 'closed',
|
|
state_reason: stateReason,
|
|
});
|
|
}
|
|
|
|
// /open or /reopen
|
|
if (body.includes('/open') || body.includes('/reopen')) {
|
|
console.log('Reopening issue');
|
|
await github.rest.issues.update({
|
|
owner, repo, issue_number: issueNumber,
|
|
state: 'open',
|
|
});
|
|
}
|