[Resource]: Claude-Ally-Health: A Privacy-First, Local AI Medical Assistant Powered by Claude Code #318
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Protect Labels from Unauthorized Changes | |
| on: | |
| issues: | |
| types: [labeled, unlabeled] | |
| jobs: | |
| check-label-permissions: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| - name: Check if label change is authorized | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const actor = context.actor; | |
| const action = context.payload.action; | |
| const label = context.payload.label.name; | |
| const issue_number = context.issue.number; | |
| // Labels that should be protected | |
| const protectedLabels = [ | |
| 'resource-submission', | |
| 'validation-passed', | |
| 'validation-failed', | |
| 'approved', | |
| 'rejected', | |
| 'changes-requested', | |
| 'pr-created', | |
| 'error-creating-pr' | |
| ]; | |
| // Check if this is a protected label | |
| if (!protectedLabels.includes(label)) { | |
| console.log(`Label "${label}" is not protected, allowing change`); | |
| return; | |
| } | |
| // WORKAROUND: Allow adding template labels (resource-submission and pending-validation) | |
| // GitHub attributes labels from issue templates as being added by the issue author, | |
| // not by GitHub itself. Without this exception, the protect-labels workflow would | |
| // incorrectly flag and revert these template-defined labels as unauthorized changes. | |
| if (action === 'labeled' && (label === 'resource-submission' || label === 'pending-validation')) { | |
| console.log(`Allowing template label "${label}" to be added (used by issue templates)`); | |
| return; | |
| } | |
| // Check if actor has write permissions | |
| const actorPermission = context.payload.sender.author_association; | |
| const isRepoOwner = context.repo.owner === actor; | |
| console.log(`Actor: ${actor}, Author Association: ${actorPermission}, Repo Owner: ${context.repo.owner}, Is Repo Owner: ${isRepoOwner}`); | |
| // Check if authorized - include repo owner check for forks | |
| const isAuthorized = isRepoOwner || ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(actorPermission); | |
| if (isAuthorized) { | |
| console.log(`User ${actor} is authorized to change labels`); | |
| return; | |
| } | |
| // Unauthorized change detected - revert it | |
| console.log(`Unauthorized label change by ${actor} - reverting`); | |
| try { | |
| if (action === 'labeled') { | |
| // Remove the unauthorized label | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue_number, | |
| name: label | |
| }); | |
| } else if (action === 'unlabeled') { | |
| // Re-add the removed label | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue_number, | |
| labels: [label] | |
| }); | |
| } | |
| // Add a comment explaining the reversion | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue_number, | |
| body: `⚠️ **Unauthorized label change detected**\n\n@${actor} - The \`${label}\` label is protected and can only be modified by maintainers. Your change has been reverted.\n\nProtected labels are managed automatically by our workflows or by maintainers only.` | |
| }); | |
| } catch (error) { | |
| console.error('Error reverting label change:', error); | |
| } |