mirror of
https://github.com/trailofbits/skills
synced 2026-06-21 14:12:00 +00:00
f09e5c729a
* Remove legacy codex compatiblity scripts/shims. Codex supports claude plugins so this shouldn't be necessary. Add a script to test the plugin loadablility in both claude and codex * fix: resolve code review findings for PR #173 Review findings addressed (4 reviewers: pr-review-toolkit agents, Codex gpt-5.3-codex, direct diff review): P2 fixed: - Bump versions for the 5 substantively changed plugins in both plugin.json and marketplace.json (gh-cli 1.5.0 new skill, claude-in-chrome-troubleshooting 1.1.0 skill rename, modern-python 1.5.1 / skill-improver 1.0.3 hooks change, zeroize-audit 0.1.1 MCP config relocation) so clients pick up the changes - README Codex install: replace unpasteable /plugins slash-command block with verified CLI syntax (codex plugin marketplace add) - check_claude_loadability: parse_json_output now fails fast with command context on empty CLI output instead of returning None - check_codex_loadability: surface skipped RPC error messages in timeout failures instead of a bare TimeoutError P3 fixed: - Both checkers: error out when marketplace.json lists no plugins instead of passing vacuously Dismissed: - @latest CLI installs in validate.yml: deliberate; the check validates against the clients users actually run - select.select portability: CI-only script on ubuntu-latest - Divergent mcpServers validation between checkers: intentional; the Codex checker enforces the repo's .mcp.json convention Verified: ruff, prek, validate_plugin_metadata.py, and both loadability checks pass end-to-end (39 plugins, 74 skills, 2 MCP servers load in Claude Code and Codex) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Dan Guido <dan@trailofbits.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
110 lines
3.8 KiB
YAML
110 lines
3.8 KiB
YAML
name: Validate
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
validate:
|
|
name: Validate plugins and skills
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Validate SKILL.md frontmatter
|
|
run: |
|
|
echo "Checking SKILL.md frontmatter..."
|
|
python3 -c "
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
errors = []
|
|
skill_count = 0
|
|
|
|
for root, dirs, files in os.walk('plugins'):
|
|
for f in files:
|
|
if f == 'SKILL.md':
|
|
path = os.path.join(root, f)
|
|
skill_count += 1
|
|
with open(path) as fp:
|
|
content = fp.read()
|
|
|
|
# Check for frontmatter
|
|
if not content.startswith('---'):
|
|
errors.append(f'{path}: missing YAML frontmatter')
|
|
continue
|
|
|
|
# Extract frontmatter
|
|
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
|
|
if not match:
|
|
errors.append(f'{path}: malformed frontmatter')
|
|
continue
|
|
|
|
frontmatter = match.group(1)
|
|
|
|
# Check for required fields
|
|
if 'name:' not in frontmatter:
|
|
errors.append(f'{path}: missing \"name\" in frontmatter')
|
|
if 'description:' not in frontmatter:
|
|
errors.append(f'{path}: missing \"description\" in frontmatter')
|
|
|
|
if errors:
|
|
for e in errors:
|
|
print(f'ERROR: {e}', file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print(f'All {skill_count} SKILL.md files have valid frontmatter')
|
|
"
|
|
|
|
- name: Check for hardcoded paths
|
|
run: |
|
|
echo "Checking for hardcoded user paths..."
|
|
# Exclude /path/to (example paths) and /home/vscode (standard devcontainer user)
|
|
if grep -rPn '(?<![a-zA-Z])(/home/[a-z]|/Users/[A-Z])' plugins/ --include='*.md' --include='*.py' --include='*.json' | grep -v '/path/to' | grep -v '/home/vscode'; then
|
|
echo "ERROR: Found hardcoded user paths (see above)"
|
|
exit 1
|
|
fi
|
|
echo "No hardcoded user paths found"
|
|
|
|
- name: Check for personal emails
|
|
run: |
|
|
echo "Checking for personal emails..."
|
|
if grep -r '@trailofbits.com' . --include='*.json' --include='*.toml' | grep -v 'opensource@trailofbits.com' | grep -v '.git'; then
|
|
echo "ERROR: Found personal emails (should use opensource@trailofbits.com)"
|
|
exit 1
|
|
fi
|
|
echo "No personal emails found"
|
|
|
|
- name: Validate plugin metadata
|
|
run: python3 .github/scripts/validate_plugin_metadata.py
|
|
|
|
- name: Install Claude Code CLI
|
|
run: |
|
|
npm install --global --prefix "$RUNNER_TEMP/claude-cli" @anthropic-ai/claude-code@latest
|
|
echo "$RUNNER_TEMP/claude-cli/bin" >> "$GITHUB_PATH"
|
|
"$RUNNER_TEMP/claude-cli/bin/claude" --version
|
|
|
|
- name: Check Claude loadability
|
|
run: python3 .github/scripts/check_claude_loadability.py
|
|
|
|
- name: Install Codex CLI
|
|
run: |
|
|
npm install --global --prefix "$RUNNER_TEMP/codex-cli" @openai/codex@latest
|
|
echo "$RUNNER_TEMP/codex-cli/bin" >> "$GITHUB_PATH"
|
|
"$RUNNER_TEMP/codex-cli/bin/codex" --version
|
|
|
|
- name: Check Codex loadability
|
|
run: python3 .github/scripts/check_codex_loadability.py
|