Skip to content

[Resource]: Claude-Ally-Health: A Privacy-First, Local AI Medical Assistant Powered by Claude Code #318

[Resource]: Claude-Ally-Health: A Privacy-First, Local AI Medical Assistant Powered by Claude Code

[Resource]: Claude-Ally-Health: A Privacy-First, Local AI Medical Assistant Powered by Claude Code #318

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);
}