112 lines
3.6 KiB
YAML
112 lines
3.6 KiB
YAML
name: Skill Frontmatter Check
|
|
|
|
on:
|
|
pull_request_target:
|
|
types: [opened, synchronize]
|
|
branches: [main]
|
|
paths:
|
|
- "**/SKILL.md"
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
check-frontmatter:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Check SKILL.md frontmatter via API
|
|
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
|
with:
|
|
retries: 3
|
|
script: |
|
|
const DISALLOWED_FIELDS = new Set(['stages']);
|
|
const DISALLOWED_PREFIXES = ['owner_'];
|
|
|
|
const files = await github.paginate(
|
|
github.rest.pulls.listFiles,
|
|
{
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: context.payload.pull_request.number,
|
|
per_page: 100
|
|
}
|
|
);
|
|
|
|
const skillFiles = files
|
|
.filter(f => f.filename.endsWith('SKILL.md') && f.status !== 'removed');
|
|
|
|
if (skillFiles.length === 0) {
|
|
core.info('No SKILL.md files changed.');
|
|
return;
|
|
}
|
|
|
|
const violations = [];
|
|
|
|
for (const file of skillFiles) {
|
|
const { data } = await github.rest.repos.getContent({
|
|
owner: context.payload.pull_request.head.repo.owner.login,
|
|
repo: context.payload.pull_request.head.repo.name,
|
|
path: file.filename,
|
|
ref: context.payload.pull_request.head.sha
|
|
});
|
|
|
|
const content = Buffer.from(data.content, 'base64').toString('utf-8');
|
|
const lines = content.split('\n');
|
|
|
|
if (lines[0] !== '---') continue;
|
|
|
|
const disallowed = [];
|
|
for (let i = 1; i < lines.length; i++) {
|
|
if (lines[i] === '---') break;
|
|
const match = lines[i].match(/^([a-zA-Z_][a-zA-Z0-9_-]*):/);
|
|
if (match && (DISALLOWED_FIELDS.has(match[1]) || DISALLOWED_PREFIXES.some(p => match[1].startsWith(p)))) {
|
|
disallowed.push(match[1]);
|
|
}
|
|
}
|
|
|
|
if (disallowed.length > 0) {
|
|
violations.push({ path: file.filename, fields: disallowed });
|
|
}
|
|
}
|
|
|
|
if (violations.length === 0) {
|
|
core.info('All SKILL.md files pass frontmatter check.');
|
|
return;
|
|
}
|
|
|
|
const list = violations
|
|
.map(v => `- \`${v.path}\`: ${v.fields.map(f => '`' + f + '`').join(', ')}`)
|
|
.join('\n');
|
|
|
|
const body = [
|
|
'⚠️ **PR closed automatically.**',
|
|
'',
|
|
'SKILL.md frontmatter contains fields that are not permitted in this public repository:',
|
|
'',
|
|
list,
|
|
'',
|
|
'Please remove these fields and reopen the PR.'
|
|
].join('\n');
|
|
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: context.payload.pull_request.number,
|
|
body
|
|
});
|
|
|
|
await github.rest.pulls.update({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: context.payload.pull_request.number,
|
|
state: 'closed'
|
|
});
|
|
|
|
core.setFailed('SKILL.md files contained disallowed frontmatter fields.');
|