Skip to content

feat(profile): protectionFloors, and label diffs that loosen protecti… #173

feat(profile): protectionFloors, and label diffs that loosen protecti…

feat(profile): protectionFloors, and label diffs that loosen protecti… #173

Workflow file for this run

name: validate
# This workflow runs scripts from the checked-out ref, including on pull requests.
# Least-privilege token, and no credentials left in .git/config for those scripts to reach.
permissions:
contents: read
on:
push:
branches: [main]
pull_request:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Manifests are valid JSON, and match the marketplace
run: |
python3 - <<'EOF'
import json, sys, pathlib
mp = json.loads(pathlib.Path('.claude-plugin/marketplace.json').read_text())
fail = False
for entry in mp['plugins']:
src = entry['source'].lstrip('./')
manifest = pathlib.Path(src) / '.claude-plugin' / 'plugin.json'
if not manifest.exists():
print(f"FAIL {entry['name']}: no manifest at {manifest}"); fail = True; continue
pj = json.loads(manifest.read_text())
if pj['name'] != entry['name']:
print(f"FAIL {src}: manifest name {pj['name']!r} != marketplace {entry['name']!r}"); fail = True
if pj.get('version') != entry.get('version'):
print(f"FAIL {entry['name']}: version {pj.get('version')!r} != marketplace {entry.get('version')!r}"); fail = True
sys.exit(1 if fail else 0)
EOF
- name: Agent Plugins v1.0.0 manifests match and stay within the closed schema
run: |
python3 - <<'EOF'
import json, sys, pathlib
ALLOWED = {
'$schema', 'name', 'version', 'description', 'author',
'homepage', 'repository', 'license', 'keywords', 'extensions',
}
SCHEMA_URL = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json'
mp = json.loads(pathlib.Path('.claude-plugin/marketplace.json').read_text())
fail = False
for entry in mp['plugins']:
src = entry['source'].lstrip('./')
manifest = pathlib.Path(src) / 'plugin.json'
if not manifest.exists():
continue # optional: not every plugin has to opt into the open spec
pj = json.loads(manifest.read_text())
extra = set(pj) - ALLOWED
if extra:
print(f"FAIL {manifest}: fields outside the closed schema: {sorted(extra)}"); fail = True
if pj.get('$schema') != SCHEMA_URL:
print(f"FAIL {manifest}: \\$schema is {pj.get('$schema')!r}, expected {SCHEMA_URL!r}"); fail = True
if pj.get('name') != entry['name']:
print(f"FAIL {manifest}: name {pj.get('name')!r} != marketplace {entry['name']!r}"); fail = True
if pj.get('version') != entry.get('version'):
print(f"FAIL {manifest}: version {pj.get('version')!r} != marketplace {entry.get('version')!r}"); fail = True
sys.exit(1 if fail else 0)
EOF
- name: Every skill has frontmatter with name and description
run: |
python3 - <<'EOF'
import sys, pathlib, re
fail = False
for skill in pathlib.Path('plugins').glob('*/skills/*/SKILL.md'):
text = skill.read_text()
m = re.match(r'^---\n(.*?)\n---\n', text, re.S)
if not m:
print(f"FAIL {skill}: no YAML frontmatter"); fail = True; continue
fm = m.group(1)
if fm != fm.strip() or re.search(r'(?m)^[ \t]*$', fm):
print(f"FAIL {skill}: blank line inside frontmatter"); fail = True
for field in ('name', 'description'):
if not re.search(rf'^{field}:', fm, re.M):
print(f"FAIL {skill}: frontmatter missing {field}"); fail = True
sys.exit(1 if fail else 0)
EOF
- name: The coverage-ratchet shell helpers behave, and fail closed
run: ./scripts/test-coverage.sh
- name: The repo-profile helpers resolve and diff correctly, and fail closed
run: ./scripts/test-profile.sh
- name: The PR-template helper checks headings and resolves prTemplateSource correctly
run: ./scripts/test-pr-template-check.sh
- name: The repo-ops pr-template-guard and skip-label-race-guard hooks behave, and fail closed
run: ./scripts/test-repo-ops-hooks.sh
- name: The research-radar harvester fails closed, windows from its mark, and dedupes
run: python3 scripts/test-research-radar.py
- name: A documented `gh pr merge --auto` always pins the head commit
run: python3 scripts/check-merge-arming.py
- name: Vendored reference docs are in sync with the canonical
run: ./scripts/sync-references.sh --check
- name: Links resolve in both layouts; prose section references still exist
run: python3 scripts/check-links.py